From d295638b38917a637fc80df33208eedcbc57214f Mon Sep 17 00:00:00 2001 From: Justin Baur <19896123+justindbaur@users.noreply.github.com> Date: Wed, 25 Feb 2026 14:01:35 -0500 Subject: [PATCH 1/3] Add docs for how to add metrics and traces --- docs/contributing/code-style/csharp.md | 78 ++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/docs/contributing/code-style/csharp.md b/docs/contributing/code-style/csharp.md index 918663f1b..146114a88 100644 --- a/docs/contributing/code-style/csharp.md +++ b/docs/contributing/code-style/csharp.md @@ -273,6 +273,76 @@ public async Task Delete(Guid id) {} public async Task PostDelete(Guid id) {} ``` +### Telemetry + +Bitwarden uses OpenTelemetry for collecting metrics and traces to enable diagnostics collection +making it easier to get to the bottom of issues. + +#### Avoiding PII + +Telemetry data may be collected, stored, and inspected externally. Metrics and traces must never +contain user personally identifiable information (PII). Examples of PII to avoid in metric +attributes, trace tags, and span attributes: + +- User IDs, email addresses, or usernames +- Vault item names or contents +- Organization names or IDs +- IP addresses or device identifiers + +Use aggregate values (counts, durations, error codes) rather than any data tied to a specific user +or their vault data. + +#### Metrics + +Custom metrics are enabled in our services when using our in-house server SDK. They should be used +via the [`IMeterFactory`][meter-factory] that is available from our DI container. + +```csharp +public class MyFeatureMetrics +{ + private readonly Counter _requestCounter; + private readonly Histogram _processingDuration; + + public MyFeatureMetrics(IMeterFactory meterFactory) + { + var meter = meterFactory.Create("Bitwarden.MyFeature"); + _requestCounter = meter.CreateCounter( + "bitwarden.myfeature.requests", + unit: "{requests}", + description: "Number of requests processed"); + _processingDuration = meter.CreateHistogram( + "bitwarden.myfeature.processing.duration", + unit: "s", + description: "Duration of request processing"); + } +} +``` + +The meter name should be a dot separated, pascal case, hierarchy of names similar to a namespace. +The name should begin with `Bitwarden.` to enable automatic collection of that metric. The +instrument names should follow [Open Telemetry naming guidelines][otel-naming-guidelines] +([permalink][otel-naming-guidelines-permalink]). + +#### Traces + +Custom traces can be created using [`ActivitySource`][activity-source]. + +```csharp +public class MyService +{ + private static readonly ActivitySource _myActivitySource = new("Bitwarden.MyFeature"); + + public void DoWork() + { + using var activity = _myActivitySource.StartActivity("MyOperation"); + // ... + } +} +``` + +The activity source name should be a dot separated, pascal case, hierarchy of names similar to a +namespace. The name should begin with `Bitwarden.` to enable automatic collection of that trace. + [null-forgiving]: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-forgiving [null-state-attributes]: @@ -287,3 +357,11 @@ public async Task PostDelete(Guid id) {} https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-9.0#register-groups-of-services-with-extension-methods [guid-newguid]: https://learn.microsoft.com/en-us/dotnet/api/system.guid.newguid [corehelpers-generatecomb]: https://fastuuid.com/learn-about-uuids/comb-guids +[meter-factory]: + https://learn.microsoft.com/en-us/dotnet/core/diagnostics/metrics-instrumentation?source=recommendations#get-a-meter-via-dependency-injection +[otel-naming-guidelines]: + https://github.com/open-telemetry/semantic-conventions/blob/main/docs/general/naming.md +[otel-naming-guidelines-permalink]: + https://github.com/open-telemetry/semantic-conventions/blob/084f18ed184d297545af4274fa4681feca3ecf6e/docs/general/naming.md +[activity-source]: + https://learn.microsoft.com/en-us/dotnet/core/diagnostics/distributed-tracing-instrumentation-walkthroughs#activitysource From 53c19a27f7dd4184defd2f2ff6cf3c1b2a736c8b Mon Sep 17 00:00:00 2001 From: Justin Baur <19896123+justindbaur@users.noreply.github.com> Date: Thu, 5 Mar 2026 15:40:14 -0500 Subject: [PATCH 2/3] Update docs/contributing/code-style/csharp.md Co-authored-by: Matt Bishop --- docs/contributing/code-style/csharp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributing/code-style/csharp.md b/docs/contributing/code-style/csharp.md index 146114a88..fcca906c7 100644 --- a/docs/contributing/code-style/csharp.md +++ b/docs/contributing/code-style/csharp.md @@ -340,7 +340,7 @@ public class MyService } ``` -The activity source name should be a dot separated, pascal case, hierarchy of names similar to a +The activity source name should be a dot-separated, Pascal case, hierarchy of names similar to a namespace. The name should begin with `Bitwarden.` to enable automatic collection of that trace. [null-forgiving]: From 8ac20a364ef2c06d026da4554668d913dc5132e5 Mon Sep 17 00:00:00 2001 From: Justin Baur <19896123+justindbaur@users.noreply.github.com> Date: Thu, 5 Mar 2026 16:05:36 -0500 Subject: [PATCH 3/3] Add OpenTelemetry link --- docs/contributing/code-style/csharp.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/contributing/code-style/csharp.md b/docs/contributing/code-style/csharp.md index fcca906c7..aef6b6647 100644 --- a/docs/contributing/code-style/csharp.md +++ b/docs/contributing/code-style/csharp.md @@ -275,8 +275,8 @@ public async Task PostDelete(Guid id) {} ### Telemetry -Bitwarden uses OpenTelemetry for collecting metrics and traces to enable diagnostics collection -making it easier to get to the bottom of issues. +Bitwarden uses [OpenTelemetry][open-telemetry] for collecting metrics and traces to enable +diagnostics collection making it easier to get to the bottom of issues. #### Avoiding PII @@ -357,6 +357,7 @@ namespace. The name should begin with `Bitwarden.` to enable automatic collectio https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-9.0#register-groups-of-services-with-extension-methods [guid-newguid]: https://learn.microsoft.com/en-us/dotnet/api/system.guid.newguid [corehelpers-generatecomb]: https://fastuuid.com/learn-about-uuids/comb-guids +[open-telemetry]: https://opentelemetry.io/docs/ [meter-factory]: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/metrics-instrumentation?source=recommendations#get-a-meter-via-dependency-injection [otel-naming-guidelines]: