Repository: edgexfoundry/device-sdk-go (go)

Issue:
Device Last Connected
<!--🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅

Oh hi there! 😄 

To expedite issue processing please search open and closed issues before submitting a new one.
Existing issues often contain information about workarounds, resolution, or progress updates.

Please do not remove sections of this template when submitting your issue.  If the section is not relevant to your issue, leave the section but enter "n/a" for not applicable.

Note some sections are marked "REQUIRED" and must be provided.  Never mark required sections "n/a".

🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅-->


# 🚀 Feature Request

### Relevant Package [**REQUIRED**]
<!-- Can you pin-point one or more EdgeX services the are relevant for this feature request? -->
<!-- ✍️edit: --> This feature request is for when Device commands (Get & Set) are executed and when a Device sends Async data


### Description [**REQUIRED**]
<!-- ✍️-->Implement Last Connect capability using a `Gauge` metric for each device that the service is managing.

The `gometrics.Gauge` metrics for each device can be stored in the Device Cache here with new access by name functions.
https://github.com/edgexfoundry/device-sdk-go/blob/main/internal/cache/devices.go#L30C1-L33C2
```go
type deviceCache struct {
	deviceMap map[string]*models.Device // key is Device name
        lastConnected map[string] gometrics.Gauge
	mutex     sync.RWMutex
}
```
The metric is added/removed when a device is added or removed. The metric must be registered/unregistered vi the `MetricsManager`
The naming scheme for the metric is `LastConnected-{device-name}` . We may need to deal with any special characters in the name that might impact the JSON when the metric is reported via the MessageBus. This may be an enhancement to metrics.Reporter.

Here are examples from App SDK for storing, initializing metrics for function pipelines:

https://github.com/edgexfoundry/app-functions-sdk-go/blob/main/pkg/interfaces/service.go#L61-L63
https://github.com/edgexfoundry/app-functions-sdk-go/blob/main/internal/runtime/runtime.go#L57
https://github.com/edgexfoundry/app-functions-sdk-go/blob/main/internal/runtime/runtime.go#L183-L199
This uses similar naming scheme. Base metric name with pipeline name appended.

### Describe the solution you'd like
<!-- ✍️--> If you have a solution in mind, please describe it.


### Describe alternatives you've considered
<!-- ✍️--> Have you considered any alternative solutions or workarounds?


Pull request:
feat: Add device last connected metrics
fixes #1470. Add device last connected metrics to Get/Set command.

<!-- Expected Commit Message Description (imported automatically by GitHub) -->
<!-- Must conform to [conventional commits guidelines](https://github.com/edgexfoundry/device-sdk-go/blob/main/.github/Contributing.md) -->
<!-- Expected Commit message must contain Closes/Fixes #IssueNumber statement when there is a related issue -->

<!-- Add additional detailed description of need for change if no related issue -->

**If your build fails** due to your commit message not passing the build checks, please review the guidelines here: https://github.com/edgexfoundry/device-sdk-go/blob/main/.github/Contributing.md

## PR Checklist
Please check if your PR fulfills the following requirements:

- [x] I am not introducing a breaking change (if you are, flag in conventional commit message with `BREAKING CHANGE:` describing the break)
- [x] I am not introducing a new dependency (add notes below if you are)
- [x] I have added unit tests for the new feature or bug fix (if not, why?)
- [x] I have fully tested (add details below) this the new feature or bug fix (if not, why?)
- [x] I have opened a PR for the related docs change (if not, why?) - https://github.com/edgexfoundry/edgex-docs/pull/1231
  <link to docs PR>

## Testing Instructions
<!-- How can the reviewers test your change? -->

## New Dependency Instructions (If applicable)
<!-- Please follow [vetting instructions](https://wiki.edgexfoundry.org/display/FA/Vetting+Process+for+3rd+Party+Dependencies) and place results here -->

Patch:
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 00000000..391859a0
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,11 @@
+name: Create Release
+on:
+  push:
+    tags:
+      - 'v*.*.*'
+      - '!v*-dev*'
+jobs:
+  release:
+    uses: edgexfoundry/edgex-global-pipelines/.github/workflows/release.yml@stable
+    permissions:
+      contents: write
\ No newline at end of file
diff --git a/go.mod b/go.mod
index 405c98e8..d6e0a425 100644
--- a/go.mod
+++ b/go.mod
@@ -4,9 +4,9 @@ go 1.21
 
 require (
 	github.com/OneOfOne/xxhash v1.2.8
-	github.com/edgexfoundry/go-mod-bootstrap/v3 v3.1.0-dev.40
+	github.com/edgexfoundry/go-mod-bootstrap/v3 v3.1.0-dev.44
 	github.com/edgexfoundry/go-mod-core-contracts/v3 v3.1.0-dev.15
-	github.com/edgexfoundry/go-mod-messaging/v3 v3.1.0-dev.21
+	github.com/edgexfoundry/go-mod-messaging/v3 v3.1.0-dev.24
 	github.com/google/uuid v1.3.1
 	github.com/hashicorp/go-multierror v1.1.1
 	github.com/labstack/echo/v4 v4.11.1
@@ -21,9 +21,9 @@ require (
 	github.com/cenkalti/backoff v2.2.1+incompatible // indirect
 	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
 	github.com/eclipse/paho.mqtt.golang v1.4.3 // indirect
-	github.com/edgexfoundry/go-mod-configuration/v3 v3.1.0-dev.6 // indirect
-	github.com/edgexfoundry/go-mod-registry/v3 v3.1.0-dev.6 // indirect
-	github.com/edgexfoundry/go-mod-secrets/v3 v3.1.0-dev.6 // indirect
+	github.com/edgexfoundry/go-mod-configuration/v3 v3.1.0-dev.7 // indirect
+	github.com/edgexfoundry/go-mod-registry/v3 v3.1.0-dev.7 // indirect
+	github.com/edgexfoundry/go-mod-secrets/v3 v3.1.0-dev.9 // indirect
 	github.com/fatih/color v1.14.1 // indirect
 	github.com/fxamacker/cbor/v2 v2.5.0 // indirect
 	github.com/gabriel-vasile/mimetype v1.4.2 // indirect
@@ -37,7 +37,7 @@ require (
 	github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
 	github.com/golang/protobuf v1.5.2 // indirect
 	github.com/gorilla/websocket v1.5.0 // indirect
-	github.com/hashicorp/consul/api v1.24.0 // indirect
+	github.com/hashicorp/consul/api v1.25.1 // indirect
 	github.com/hashicorp/errwrap v1.1.0 // indirect
 	github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
 	github.com/hashicorp/go-hclog v1.5.0 // indirect
@@ -45,7 +45,7 @@ require (
 	github.com/hashicorp/go-rootcerts v1.0.2 // indirect
 	github.com/hashicorp/golang-lru v0.5.4 // indirect
 	github.com/hashicorp/serf v0.10.1 // indirect
-	github.com/klauspost/compress v1.16.7 // indirect
+	github.com/klauspost/compress v1.17.0 // indirect
 	github.com/labstack/gommon v0.4.0 // indirect
 	github.com/leodido/go-urn v1.2.4 // indirect
 	github.com/mattn/go-colorable v0.1.13 // indirect
@@ -55,8 +55,8 @@ require (
 	github.com/mitchellh/go-homedir v1.1.0 // indirect
 	github.com/mitchellh/mapstructure v1.5.0 // indirect
 	github.com/mitchellh/reflectwalk v1.0.2 // indirect
-	github.com/nats-io/nats.go v1.28.0 // indirect
-	github.com/nats-io/nkeys v0.4.4 // indirect
+	github.com/nats-io/nats.go v1.30.1 // indirect
+	github.com/nats-io/nkeys v0.4.5 // indirect
 	github.com/nats-io/nuid v1.0.1 // indirect
 	github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
 	github.com/spiffe/go-spiffe/v2 v2.1.6 // indirect
@@ -65,13 +65,13 @@ require (
 	github.com/valyala/fasttemplate v1.2.2 // indirect
 	github.com/x448/float16 v0.8.4 // indirect
 	github.com/zeebo/errs v1.3.0 // indirect
-	golang.org/x/crypto v0.12.0 // indirect
+	golang.org/x/crypto v0.13.0 // indirect
 	golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect
 	golang.org/x/mod v0.8.0 // indirect
 	golang.org/x/net v0.13.0 // indirect
 	golang.org/x/sync v0.2.0 // indirect
-	golang.org/x/sys v0.11.0 // indirect
-	golang.org/x/text v0.12.0 // indirect
+	golang.org/x/sys v0.12.0 // indirect
+	golang.org/x/text v0.13.0 // indirect
 	golang.org/x/time v0.3.0 // indirect
 	golang.org/x/tools v0.6.0 // indirect
 	google.golang.org/genproto v0.0.0-20230223222841-637eb2293923 // indirect
diff --git a/go.sum b/go.sum
index fa19fa20..e9cb1cd0 100644
--- a/go.sum
+++ b/go.sum
@@ -28,18 +28,18 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/eclipse/paho.mqtt.golang v1.4.3 h1:2kwcUGn8seMUfWndX0hGbvH8r7crgcJguQNCyp70xik=
 github.com/eclipse/paho.mqtt.golang v1.4.3/go.mod h1:CSYvoAlsMkhYOXh/oKyxa8EcBci6dVkLCbo5tTC1RIE=
-github.com/edgexfoundry/go-mod-bootstrap/v3 v3.1.0-dev.40 h1:EPERY7NeYvHAgv/M302kb13qXAtsIV4fjJzUjiARHR0=
-github.com/edgexfoundry/go-mod-bootstrap/v3 v3.1.0-dev.40/go.mod h1:/QPYSj3l+BhaBTC2qvnhf8jqKlXfMwWPBuKD5+RpTPQ=
-github.com/edgexfoundry/go-mod-configuration/v3 v3.1.0-dev.6 h1:TW6IrTV5DuWMM2J0Y8gBpi4iSc2dHZiZuo4WEulgYwY=
-github.com/edgexfoundry/go-mod-configuration/v3 v3.1.0-dev.6/go.mod h1:5knpeLSwjXrptQy2FgLN/lWrBQxcnRBYz1CXxupTN18=
+github.com/edgexfoundry/go-mod-bootstrap/v3 v3.1.0-dev.44 h1:pkmea4M5OMSLjlsuhp9q0/vc2W3S6mQN/Q8H3Y89ztI=
+github.com/edgexfoundry/go-mod-bootstrap/v3 v3.1.0-dev.44/go.mod h1:tZj4WRRT5R7yv9gDv7brYTT75LcLu4Tj6fX30Ou2mPQ=
+github.com/edgexfoundry/go-mod-configuration/v3 v3.1.0-dev.7 h1:2YukEsMQ1juhMtsyiwQONKaZz2GRbKcevCw33oFyptw=
+github.com/edgexfoundry/go-mod-configuration/v3 v3.1.0-dev.7/go.mod h1:Un2xgWH5Wf8rfuLZBUVcE0uPyFCHsVhzyOaY+WKnPB4=
 github.com/edgexfoundry/go-mod-core-contracts/v3 v3.1.0-dev.15 h1:hqsrrSwouLoA9zmvwlgb/h6AB1tIXx3u6WFRFTwC8GA=
 github.com/edgexfoundry/go-mod-core-contracts/v3 v3.1.0-dev.15/go.mod h1:EEqaNIvDs3c0KWtcbAF0ynrKWQb3ifocGW6xBzJTvaM=
-github.com/edgexfoundry/go-mod-messaging/v3 v3.1.0-dev.21 h1:RnABQFBuoUogQibrWpwGTX8Ws+jbrcFyMb00ZkHRkcw=
-github.com/edgexfoundry/go-mod-messaging/v3 v3.1.0-dev.21/go.mod h1:Br4En+hE/pDMHyqifAOt6EJ/QROLMGIBx+cPoS2cqns=
-github.com/edgexfoundry/go-mod-registry/v3 v3.1.0-dev.6 h1:xzXLE902+Xre1mV8VLImJ1LTI7FKRv7sHpleP1pW/PQ=
-github.com/edgexfoundry/go-mod-registry/v3 v3.1.0-dev.6/go.mod h1:F1ctOQrRKrD/aZDzbUhjuE9fJGCRP7IVAJ5kaKocXy4=
-github.com/edgexfoundry/go-mod-secrets/v3 v3.1.0-dev.6 h1:1mmrSNG7bsOhlSqC1F9L6eZwCirDPzzreivPOkp06i4=
-github.com/edgexfoundry/go-mod-secrets/v3 v3.1.0-dev.6/go.mod h1:3STtpFY9MJA3gWkpoFhT3zPhFom1+OXPuklU68i5uDk=
+github.com/edgexfoundry/go-mod-messaging/v3 v3.1.0-dev.24 h1:4I1gEJ+Qpi7Z8ouJgJEWyAv10TRYTqk0W0F2NcUbE/c=
+github.com/edgexfoundry/go-mod-messaging/v3 v3.1.0-dev.24/go.mod h1:fECirySz+ObJbTDXOK7G2cZaqJZ9KNBqkSRTm31126w=
+github.com/edgexfoundry/go-mod-registry/v3 v3.1.0-dev.7 h1:JM52VOza4Y6adtKkEoLgj4qUmM5KXU/X/7Mf4G0rtTc=
+github.com/edgexfoundry/go-mod-registry/v3 v3.1.0-dev.7/go.mod h1:HkAwzgWKvE0Nx+mvWVprVHd8r4HHciIf1Sl1wRpTB7U=
+github.com/edgexfoundry/go-mod-secrets/v3 v3.1.0-dev.9 h1:/5DZyDAyGMvU7qfX3WDC3X9NPa32SbFDB9NZzW3GSsI=
+github.com/edgexfoundry/go-mod-secrets/v3 v3.1.0-dev.9/go.mod h1:EGwVO9NxleRbFYb5w1SvdrcchCjHofZNuEP2suTCbu4=
 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
 github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
 github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
@@ -94,8 +94,8 @@ github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
 github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
 github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-github.com/hashicorp/consul/api v1.24.0 h1:u2XyStA2j0jnCiVUU7Qyrt8idjRn4ORhK6DlvZ3bWhA=
-github.com/hashicorp/consul/api v1.24.0/go.mod h1:NZJGRFYruc/80wYowkPFCp1LbGmJC9L8izrwfyVx/Wg=
+github.com/hashicorp/consul/api v1.25.1 h1:CqrdhYzc8XZuPnhIYZWH45toM0LB9ZeYr/gvpLVI3PE=
+github.com/hashicorp/consul/api v1.25.1/go.mod h1:iiLVwR/htV7mas/sy0O+XSuEnrdBUUydemjxcUrAt4g=
 github.com/hashicorp/consul/sdk v0.14.1 h1:ZiwE2bKb+zro68sWzZ1SgHF3kRMBZ94TwOCFRF4ylPs=
 github.com/hashicorp/consul/sdk v0.14.1/go.mod h1:vFt03juSzocLRFo59NkeQHHmQa6+g7oU0pfzdI1mUhg=
 github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@@ -143,8 +143,8 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
-github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
-github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
+github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
+github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
 github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
@@ -198,14 +198,14 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
 github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
-github.com/nats-io/jwt/v2 v2.5.0 h1:WQQ40AAlqqfx+f6ku+i0pOVm+ASirD4fUh+oQsiE9Ak=
-github.com/nats-io/jwt/v2 v2.5.0/go.mod h1:24BeQtRwxRV8ruvC4CojXlx/WQ/VjuwlYiH+vu/+ibI=
-github.com/nats-io/nats-server/v2 v2.9.22 h1:rzl88pqWFFrU4G00ed+JnY+uGHSLZ+3jrxDnJxzKwGA=
-github.com/nats-io/nats-server/v2 v2.9.22/go.mod h1:wEjrEy9vnqIGE4Pqz4/c75v9Pmaq7My2IgFmnykc4C0=
-github.com/nats-io/nats.go v1.28.0 h1:Th4G6zdsz2d0OqXdfzKLClo6bOfoI/b1kInhRtFIy5c=
-github.com/nats-io/nats.go v1.28.0/go.mod h1:XpbWUlOElGwTYbMR7imivs7jJj9GtK7ypv321Wp6pjc=
-github.com/nats-io/nkeys v0.4.4 h1:xvBJ8d69TznjcQl9t6//Q5xXuVhyYiSos6RPtvQNTwA=
-github.com/nats-io/nkeys v0.4.4/go.mod h1:XUkxdLPTufzlihbamfzQ7mw/VGx6ObUs+0bN5sNvt64=
+github.com/nats-io/jwt/v2 v2.5.2 h1:DhGH+nKt+wIkDxM6qnVSKjokq5t59AZV5HRcFW0zJwU=
+github.com/nats-io/jwt/v2 v2.5.2/go.mod h1:24BeQtRwxRV8ruvC4CojXlx/WQ/VjuwlYiH+vu/+ibI=
+github.com/nats-io/nats-server/v2 v2.10.1 h1:MIJ614dhOIdo71iSzY8ln78miXwrYvlvXHUyS+XdKZQ=
+github.com/nats-io/nats-server/v2 v2.10.1/go.mod h1:3PMvMSu2cuK0J9YInRLWdFpFsswKKGUS77zVSAudRto=
+github.com/nats-io/nats.go v1.30.1 h1:o5RND+GaKgzNm2IOSLmHunWs6vH0GooAAaZZitiGJWk=
+github.com/nats-io/nats.go v1.30.1/go.mod h1:dcfhUgmQNN4GJEfIb2f9R7Fow+gzBF4emzDHrVBd5qM=
+github.com/nats-io/nkeys v0.4.5 h1:Zdz2BUlFm4fJlierwvGK+yl20IAKUm7eV6AAZXEhkPk=
+github.com/nats-io/nkeys v0.4.5/go.mod h1:XUkxdLPTufzlihbamfzQ7mw/VGx6ObUs+0bN5sNvt64=
 github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
 github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@@ -275,8 +275,8 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
-golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
-golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
+golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
+golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
 golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug=
 golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
 golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
@@ -324,15 +324,15 @@ golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
-golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
+golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
-golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
+golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
 golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
diff --git a/internal/application/command.go b/internal/application/command.go
index 9f9da561..4da5ef20 100644
--- a/internal/application/command.go
+++ b/internal/application/command.go
@@ -63,6 +63,8 @@ func GetCommand(ctx context.Context, deviceName string, commandName string, quer
 
 	lc := bootstrapContainer.LoggingClientFrom(dic.Get)
 	lc.Debugf("GET Device Command successfully. Device: %s, Source: %s, %s: %s", deviceName, commandName, common.CorrelationHeader, utils.FromContext(ctx, common.CorrelationHeader))
+
+	cache.Devices().SetLastConnectedByName(deviceName)
 	return res, nil
 }
 
@@ -93,6 +95,8 @@ func SetCommand(ctx context.Context, deviceName string, commandName string, quer
 
 	lc := bootstrapContainer.LoggingClientFrom(dic.Get)
 	lc.Debugf("SET Device Command successfully. Device: %s, Source: %s, %s: %s", deviceName, commandName, common.CorrelationHeader, utils.FromContext(ctx, common.CorrelationHeader))
+
+	cache.Devices().SetLastConnectedByName(deviceName)
 	return event, nil
 }
 
diff --git a/internal/cache/devices.go b/internal/cache/devices.go
index 4e6e726e..aed517dd 100644
--- a/internal/cache/devices.go
+++ b/internal/cache/devices.go
@@ -1,6 +1,6 @@
 // -*- Mode: Go; indent-tabs-mode: t -*-
 //
-// Copyright (C) 2020-2021 IOTech Ltd
+// Copyright (C) 2020-2023 IOTech Ltd
 //
 // SPDX-License-Identifier: Apache-2.0
 
@@ -8,10 +8,21 @@ package cache
 
 import (
 	"fmt"
+	"strings"
 	"sync"
+	"time"
 
+	bootstrapContainer "github.com/edgexfoundry/go-mod-bootstrap/v3/bootstrap/container"
+	"github.com/edgexfoundry/go-mod-bootstrap/v3/di"
 	"github.com/edgexfoundry/go-mod-core-contracts/v3/errors"
 	"github.com/edgexfoundry/go-mod-core-contracts/v3/models"
+
+	gometrics "github.com/rcrowley/go-metrics"
+)
+
+const (
+	deviceNameText      = "{DeviceName}"
+	lastConnectedPrefix = "LastConnected-" + deviceNameText
 )
 
 var (
@@ -25,24 +36,56 @@ type DeviceCache interface {
 	Update(device models.Device) errors.EdgeX
 	RemoveByName(name string) errors.EdgeX
 	UpdateAdminState(name string, state models.AdminState) errors.EdgeX
+	SetLastConnectedByName(name string)
+	GetLastConnectedByName(name string) int64
 }
 
 type deviceCache struct {
-	deviceMap map[string]*models.Device // key is Device name
-	mutex     sync.RWMutex
+	deviceMap     map[string]*models.Device // key is Device name
+	mutex         sync.RWMutex
+	dic           *di.Container
+	lastConnected map[string]gometrics.Gauge
 }
 
-func newDeviceCache(devices []models.Device) DeviceCache {
+func newDeviceCache(devices []models.Device, dic *di.Container) DeviceCache {
 	defaultSize := len(devices)
 	dMap := make(map[string]*models.Device, defaultSize)
 	for i, d := range devices {
 		dMap[d.Name] = &devices[i]
 	}
 
-	dc = &deviceCache{deviceMap: dMap}
+	dc = &deviceCache{deviceMap: dMap, dic: dic}
+	lastConnectedMetrics := make(map[string]gometrics.Gauge)
+	for _, d := range devices {
+		deviceMetric := gometrics.NewGauge()
+		registerMetric(d.Name, deviceMetric, dic)
+		lastConnectedMetrics[d.Name] = deviceMetric
+	}
+	dc.lastConnected = lastConnectedMetrics
+
 	return dc
 }
 
+func registerMetric(deviceName string, metric interface{}, dic *di.Container) {
+	metricsManager := bootstrapContainer.MetricsManagerFrom(dic.Get)
+	lc := bootstrapContainer.LoggingClientFrom(dic.Get)
+	registeredName := strings.Replace(lastConnectedPrefix, deviceNameText, deviceName, 1)
+
+	err := metricsManager.Register(registeredName, metric, map[string]string{"device": deviceName})
+	if err != nil {
+		lc.Warnf("Unable to register %s metric. Metric will not be reported : %s", registeredName, err.Error())
+	} else {
+		lc.Infof("%s metric has been registered and will be reported (if enabled)", registeredName)
+	}
+}
+
+func unregisterMetric(deviceName string, dic *di.Container) {
+	metricsManager := bootstrapContainer.MetricsManagerFrom(dic.Get)
+	registeredName := strings.Replace(lastConnectedPrefix, deviceNameText, deviceName, 1)
+
+	metricsManager.Unregister(registeredName)
+}
+
 // ForName returns a Device with the given device name.
 func (d *deviceCache) ForName(name string) (models.Device, bool) {
 	d.mutex.RLock()
@@ -85,6 +128,11 @@ func (d *deviceCache) add(device models.Device) errors.EdgeX {
 	}
 
 	d.deviceMap[device.Name] = &device
+
+	// register the lastConnected metric for the new added device
+	deviceMetric := gometrics.NewGauge()
+	registerMetric(device.Name, deviceMetric, d.dic)
+	d.lastConnected[device.Name] = deviceMetric
 	return nil
 }
 
@@ -115,6 +163,11 @@ func (d *deviceCache) removeByName(name string) errors.EdgeX {
 	}
 
 	delete(d.deviceMap, name)
+
+	// unregister the lastConnected metric for the removed device
+	unregisterMetric(name, d.dic)
+	delete(d.lastConnected, name)
+
 	return nil
 }
 
@@ -152,3 +205,21 @@ func CheckProfileNotUsed(profileName string) bool {
 func Devices() DeviceCache {
 	return dc
 }
+
+// currentTimestamp returns the current timestamp in nanoseconds
+var currentTimestamp = func() int64 {
+	return time.Now().UnixNano()
+}
+
+func (d *deviceCache) SetLastConnectedByName(name string) {
+	d.mutex.RLock()
+	defer d.mutex.RUnlock()
+
+	g := d.lastConnected[name]
+	g.Update(currentTimestamp())
+}
+
+func (d *deviceCache) GetLastConnectedByName(name string) int64 {
+	g := d.lastConnected[name]
+	return g.Value()
+}
diff --git a/internal/cache/init.go b/internal/cache/init.go
index 3258d377..41bcc105 100644
--- a/internal/cache/init.go
+++ b/internal/cache/init.go
@@ -1,6 +1,6 @@
 // -*- Mode: Go; indent-tabs-mode: t -*-
 //
-// Copyright (C) 2020-2021 IOTech Ltd
+// Copyright (C) 2020-2023 IOTech Ltd
 //
 // SPDX-License-Identifier: Apache-2.0
 
@@ -32,7 +32,7 @@ func InitCache(instanceName string, baseServiceName string, dic *di.Container) e
 	for i := range deviceRes.Devices {
 		devices[i] = dtos.ToDeviceModel(deviceRes.Devices[i])
 	}
-	newDeviceCache(devices)
+	newDeviceCache(devices, dic)
 
 	// init profile cache
 	profiles := make([]models.DeviceProfile, len(devices))
diff --git a/pkg/service/async.go b/pkg/service/async.go
index e3a103f3..80dc2e84 100644
--- a/pkg/service/async.go
+++ b/pkg/service/async.go
@@ -53,6 +53,9 @@ func (s *deviceService) sendAsyncValues(acv *sdkModels.AsyncValues, working chan
 		<-working
 	}()
 
+	// Update the LastConnected metric in deviceCache
+	cache.Devices().SetLastConnectedByName(acv.DeviceName)
+
 	if len(acv.CommandValues) == 0 {
 		s.lc.Error("Skip sending AsyncValues because the CommandValues is empty.")
 		return


Test patch:
diff --git a/internal/cache/devices_test.go b/internal/cache/devices_test.go
index eb9c2272..3a92b0f0 100644
--- a/internal/cache/devices_test.go
+++ b/internal/cache/devices_test.go
@@ -1,5 +1,5 @@
 //
-// Copyright (C) 2021 IOTech Ltd
+// Copyright (C) 2021-2023 IOTech Ltd
 //
 // SPDX-License-Identifier: Apache-2.0
 
@@ -7,9 +7,20 @@ package cache
 
 import (
 	"testing"
+	"time"
 
+	"github.com/edgexfoundry/device-sdk-go/v3/internal/config"
+	"github.com/edgexfoundry/device-sdk-go/v3/internal/container"
+
+	bootstrapContainer "github.com/edgexfoundry/go-mod-bootstrap/v3/bootstrap/container"
+	"github.com/edgexfoundry/go-mod-bootstrap/v3/bootstrap/interfaces/mocks"
+	bootstrapConfig "github.com/edgexfoundry/go-mod-bootstrap/v3/config"
+	"github.com/edgexfoundry/go-mod-bootstrap/v3/di"
+	"github.com/edgexfoundry/go-mod-core-contracts/v3/clients/logger"
 	"github.com/edgexfoundry/go-mod-core-contracts/v3/models"
+
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/mock"
 	"github.com/stretchr/testify/require"
 )
 
@@ -25,8 +36,33 @@ var newDevice = models.Device{
 	OperatingState: models.Unlocked,
 }
 
+func mockDic() *di.Container {
+	mockMetricsManager := &mocks.MetricsManager{}
+	mockMetricsManager.On("Register", mock.Anything, mock.Anything, mock.Anything).Return(nil)
+	mockMetricsManager.On("Unregister", mock.Anything)
+	return di.NewContainer(di.ServiceConstructorMap{
+		bootstrapContainer.MetricsManagerInterfaceName: func(get di.Get) interface{} {
+			return mockMetricsManager
+		},
+		bootstrapContainer.LoggingClientInterfaceName: func(get di.Get) interface{} {
+			return logger.NewMockClient()
+		},
+		container.ConfigurationName: func(get di.Get) interface{} {
+			return &config.ConfigurationStruct{
+				Writable: config.WritableInfo{
+					LogLevel: "INFO",
+				},
+				Service: bootstrapConfig.ServiceInfo{
+					EnableNameFieldEscape: true,
+				},
+			}
+		},
+	})
+}
+
 func Test_deviceCache_ForName(t *testing.T) {
-	newDeviceCache([]models.Device{testDevice})
+	dic := mockDic()
+	newDeviceCache([]models.Device{testDevice}, dic)
 
 	tests := []struct {
 		name       string
@@ -48,14 +84,16 @@ func Test_deviceCache_ForName(t *testing.T) {
 }
 
 func Test_deviceCache_All(t *testing.T) {
-	newDeviceCache([]models.Device{testDevice})
+	dic := mockDic()
+	newDeviceCache([]models.Device{testDevice}, dic)
 
 	res := dc.All()
 	require.Equal(t, len(res), len(dc.deviceMap))
 }
 
 func Test_deviceCache_Add(t *testing.T) {
-	newDeviceCache([]models.Device{testDevice})
+	dic := mockDic()
+	newDeviceCache([]models.Device{testDevice}, dic)
 
 	tests := []struct {
 		name          string
@@ -77,7 +115,8 @@ func Test_deviceCache_Add(t *testing.T) {
 }
 
 func Test_deviceCache_RemoveByName(t *testing.T) {
-	newDeviceCache([]models.Device{testDevice})
+	dic := mockDic()
+	newDeviceCache([]models.Device{testDevice}, dic)
 
 	tests := []struct {
 		name          string
@@ -99,7 +138,8 @@ func Test_deviceCache_RemoveByName(t *testing.T) {
 }
 
 func Test_deviceCache_UpdateAdminState(t *testing.T) {
-	newDeviceCache([]models.Device{testDevice})
+	dic := mockDic()
+	newDeviceCache([]models.Device{testDevice}, dic)
 
 	tests := []struct {
 		name          string
@@ -122,3 +162,26 @@ func Test_deviceCache_UpdateAdminState(t *testing.T) {
 		})
 	}
 }
+
+func Test_deviceCache_SetLastConnectedByName(t *testing.T) {
+	dic := mockDic()
+	newDeviceCache([]models.Device{testDevice}, dic)
+
+	// Make currentTimestamp return currentTimeInstant constant in unit test
+	currentTimeInstant := time.Now().UnixNano()
+	currentTimestamp = func() int64 {
+		return currentTimeInstant
+	}
+
+	dc.SetLastConnectedByName(TestDevice)
+	lastConnectedTime := dc.GetLastConnectedByName(TestDevice)
+	require.Equal(t, currentTimeInstant, lastConnectedTime)
+}
+
+func Test_deviceCache_GetLastConnectedByName(t *testing.T) {
+	dic := mockDic()
+	newDeviceCache([]models.Device{testDevice}, dic)
+
+	lastConnectedTime := dc.GetLastConnectedByName(TestDevice)
+	require.Equal(t, int64(0), lastConnectedTime)
+}
diff --git a/internal/common/utils_test.go b/internal/common/utils_test.go
index d4ad94c0..55b86392 100644
--- a/internal/common/utils_test.go
+++ b/internal/common/utils_test.go
@@ -122,6 +122,10 @@ func NewMockDIC() *di.Container {
 	pwcMock := &clientMocks.ProvisionWatcherClient{}
 	pwcMock.On("ProvisionWatchersByServiceName", context.Background(), TestDeviceService, 0, -1).Return(responses.MultiProvisionWatchersResponse{}, nil)
 
+	mockMetricsManager := &mocks.MetricsManager{}
+	mockMetricsManager.On("Register", mock.Anything, mock.Anything, mock.Anything).Return(nil)
+	mockMetricsManager.On("Unregister", mock.Anything)
+
 	return di.NewContainer(di.ServiceConstructorMap{
 		container.ConfigurationName: func(get di.Get) interface{} {
 			return configuration
@@ -141,6 +145,9 @@ func NewMockDIC() *di.Container {
 		bootstrapContainer.ProvisionWatcherClientName: func(get di.Get) interface{} {
 			return pwcMock
 		},
+		bootstrapContainer.MetricsManagerInterfaceName: func(get di.Get) interface{} {
+			return mockMetricsManager
+		},
 	})
 }
 
diff --git a/internal/controller/http/command_test.go b/internal/controller/http/command_test.go
index f0ff2074..390ffe41 100644
--- a/internal/controller/http/command_test.go
+++ b/internal/controller/http/command_test.go
@@ -16,6 +16,7 @@ import (
 	"testing"
 
 	bootstrapContainer "github.com/edgexfoundry/go-mod-bootstrap/v3/bootstrap/container"
+	bootstrapMocks "github.com/edgexfoundry/go-mod-bootstrap/v3/bootstrap/interfaces/mocks"
 	"github.com/edgexfoundry/go-mod-bootstrap/v3/di"
 	clientMocks "github.com/edgexfoundry/go-mod-core-contracts/v3/clients/interfaces/mocks"
 	"github.com/edgexfoundry/go-mod-core-contracts/v3/clients/logger"
@@ -170,6 +171,11 @@ func mockDic() *di.Container {
 	mockDriver.On("HandleReadCommands", driverErrorDevice, mock.Anything, mock.Anything).Return(nil, errors.New("ProtocolDriver returned error"))
 	mockDriver.On("HandleWriteCommands", testDevice, mock.Anything, mock.Anything, mock.Anything).Return(nil)
 	mockDriver.On("HandleWriteCommands", driverErrorDevice, mock.Anything, mock.Anything, mock.Anything).Return(errors.New("ProtocolDriver returned error"))
+
+	mockMetricsManager := &bootstrapMocks.MetricsManager{}
+	mockMetricsManager.On("Register", mock.Anything, mock.Anything, mock.Anything).Return(nil)
+	mockMetricsManager.On("Unregister", mock.Anything)
+
 	dic := di.NewContainer(di.ServiceConstructorMap{
 		container.ConfigurationName: func(get di.Get) any {
 			return &config.ConfigurationStruct{
@@ -199,6 +205,9 @@ func mockDic() *di.Container {
 				AdminState: models.Unlocked,
 			}
 		},
+		bootstrapContainer.MetricsManagerInterfaceName: func(get di.Get) interface{} {
+			return mockMetricsManager
+		},
 	})
 
 	return dic
diff --git a/internal/provision/mockdic_test.go b/internal/provision/mockdic_test.go
index 52854191..4dff1c6a 100644
--- a/internal/provision/mockdic_test.go
+++ b/internal/provision/mockdic_test.go
@@ -1,6 +1,7 @@
 // -*- Mode: Go; indent-tabs-mode: t -*-
 //
 // # Copyright (C) 2023 Intel Corporation
+// # Copyright (C) 2023 IOTech Ltd
 //
 // SPDX-License-Identifier: Apache-2.0
 package provision
@@ -10,12 +11,14 @@ import (
 	"github.com/edgexfoundry/device-sdk-go/v3/internal/config"
 	"github.com/edgexfoundry/device-sdk-go/v3/internal/container"
 	bootstrapContainer "github.com/edgexfoundry/go-mod-bootstrap/v3/bootstrap/container"
+	bootstrapMocks "github.com/edgexfoundry/go-mod-bootstrap/v3/bootstrap/interfaces/mocks"
 	"github.com/edgexfoundry/go-mod-bootstrap/v3/di"
 	clientMocks "github.com/edgexfoundry/go-mod-core-contracts/v3/clients/interfaces/mocks"
 	"github.com/edgexfoundry/go-mod-core-contracts/v3/clients/logger"
 	"github.com/edgexfoundry/go-mod-core-contracts/v3/dtos"
 	"github.com/edgexfoundry/go-mod-core-contracts/v3/dtos/responses"
 	"github.com/edgexfoundry/go-mod-core-contracts/v3/models"
+	"github.com/stretchr/testify/mock"
 )
 
 const (
@@ -96,6 +99,10 @@ func NewMockDIC() (*di.Container, *clientMocks.DeviceProfileClient) {
 	pwcMock := &clientMocks.ProvisionWatcherClient{}
 	pwcMock.On("ProvisionWatchersByServiceName", context.Background(), TestDeviceService, 0, -1).Return(responses.MultiProvisionWatchersResponse{}, nil)
 
+	mockMetricsManager := &bootstrapMocks.MetricsManager{}
+	mockMetricsManager.On("Register", mock.Anything, mock.Anything, mock.Anything).Return(nil)
+	mockMetricsManager.On("Unregister", mock.Anything)
+
 	return di.NewContainer(di.ServiceConstructorMap{
 		container.ConfigurationName: func(get di.Get) interface{} {
 			return configuration
@@ -115,5 +122,8 @@ func NewMockDIC() (*di.Container, *clientMocks.DeviceProfileClient) {
 		bootstrapContainer.ProvisionWatcherClientName: func(get di.Get) interface{} {
 			return pwcMock
 		},
+		bootstrapContainer.MetricsManagerInterfaceName: func(get di.Get) interface{} {
+			return mockMetricsManager
+		},
 	}), dpcMock
 }
diff --git a/internal/transformer/transform_test.go b/internal/transformer/transform_test.go
index cccddcbb..86566b23 100644
--- a/internal/transformer/transform_test.go
+++ b/internal/transformer/transform_test.go
@@ -12,6 +12,7 @@ import (
 	"testing"
 
 	bootstrapContainer "github.com/edgexfoundry/go-mod-bootstrap/v3/bootstrap/container"
+	bootstrapMocks "github.com/edgexfoundry/go-mod-bootstrap/v3/bootstrap/interfaces/mocks"
 	"github.com/edgexfoundry/go-mod-bootstrap/v3/di"
 	clientMocks "github.com/edgexfoundry/go-mod-core-contracts/v3/clients/interfaces/mocks"
 	"github.com/edgexfoundry/go-mod-core-contracts/v3/clients/logger"
@@ -21,6 +22,7 @@ import (
 	"github.com/edgexfoundry/go-mod-core-contracts/v3/dtos/responses"
 	"github.com/edgexfoundry/go-mod-core-contracts/v3/models"
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/mock"
 	"github.com/stretchr/testify/require"
 
 	"github.com/edgexfoundry/device-sdk-go/v3/internal/cache"
@@ -109,6 +111,10 @@ func NewMockDIC() *di.Container {
 		Device: config.DeviceInfo{MaxCmdOps: 1},
 	}
 
+	mockMetricsManager := &bootstrapMocks.MetricsManager{}
+	mockMetricsManager.On("Register", mock.Anything, mock.Anything, mock.Anything).Return(nil)
+	mockMetricsManager.On("Unregister", mock.Anything)
+
 	return di.NewContainer(di.ServiceConstructorMap{
 		bootstrapContainer.LoggingClientInterfaceName: func(get di.Get) interface{} {
 			return logger.NewMockClient()
@@ -128,6 +134,9 @@ func NewMockDIC() *di.Container {
 		container.ConfigurationName: func(get di.Get) interface{} {
 			return configuration
 		},
+		bootstrapContainer.MetricsManagerInterfaceName: func(get di.Get) interface{} {
+			return mockMetricsManager
+		},
 	})
 }
 func Test_getUniqueOrigin(t *testing.T) {