Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
59a88a1
span context for logs
abelonogov-ld Apr 7, 2026
194f3a6
feat: add logging with span context in ViewModel
abelonogov-ld Apr 7, 2026
8fe35ec
example
abelonogov-ld Apr 7, 2026
ebd4de6
fix imports
abelonogov-ld Apr 7, 2026
a48c853
refactor: remove unused `recordLog` import from observability files
abelonogov-ld Apr 8, 2026
5fd96b4
span context for logs
abelonogov-ld Apr 7, 2026
4ad509f
not used files
abelonogov-ld Apr 8, 2026
9e379d7
feat: add "Log with Context" functionality to MainPage
abelonogov-ld Apr 8, 2026
65c7ff4
refactor: rename TryInitializeAll to InitializeAll and update initial…
abelonogov-ld Apr 8, 2026
8c02db9
no opentelemetry
abelonogov-ld Apr 8, 2026
6180a09
exceptions
abelonogov-ld Apr 8, 2026
c39ec78
fix
abelonogov-ld Apr 9, 2026
9eef76e
fix
abelonogov-ld Apr 9, 2026
d798511
fix deollaction
abelonogov-ld Apr 9, 2026
b468222
span context for logs
abelonogov-ld Apr 7, 2026
6d82224
feat: add logging with span context in ViewModel
abelonogov-ld Apr 7, 2026
8451a0f
example
abelonogov-ld Apr 7, 2026
47d4355
refactor: remove unused `recordLog` import from observability files
abelonogov-ld Apr 8, 2026
4e9c443
Network Request tracking
abelonogov-ld Apr 8, 2026
073a65c
network tracing
abelonogov-ld Apr 9, 2026
071345b
fix default
abelonogov-ld Apr 9, 2026
86839b9
fix
abelonogov-ld Apr 9, 2026
be2b8d8
doc and microsoft API
abelonogov-ld Apr 9, 2026
abda519
Merge branch 'main' into andrey/maui-network
abelonogov-ld Apr 9, 2026
5a67ef2
Merge branch 'andrey/maui-network' into andrey/maui-dist-doc
abelonogov-ld Apr 9, 2026
1326918
docs: Add comment to `networkRequests` property in `OptionsBridge.swi…
abelonogov-ld Apr 9, 2026
2cf94d9
fix: Restore previous Activity context when starting a new activity i…
abelonogov-ld Apr 9, 2026
08f725b
Merge branch 'main' into andrey/maui-dist-doc
abelonogov-ld Apr 9, 2026
5f9a9ff
fix: Ensure previous Activity context is restored correctly when star…
abelonogov-ld Apr 9, 2026
7caf8e9
fix: Correctly restore previous Activity context in ObservabilityServ…
abelonogov-ld Apr 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 91 additions & 4 deletions sdk/@launchdarkly/mobile-dotnet/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,19 @@ LDObserve.RecordUpDownCounter("active_connections", 1.0);
// Record logs with severity and optional attributes
LDObserve.RecordLog(
"User performed action",
LDObserve.Severity.Info,
Severity.Info,
new Dictionary<string, object?>
{
{ "user_id", "12345" },
{ "action", "button_click" }
}
);

// Record errors with an optional cause
// Record errors from an exception
var exception = new Exception("Something went wrong", new InvalidOperationException("root cause"));
LDObserve.RecordError(exception);

// Or record errors from a message string
LDObserve.RecordError("Something went wrong", "The underlying cause of the error.");
```

Expand All @@ -109,7 +113,7 @@ Use `RecordLog` to emit structured log records with a severity level and optiona
```csharp
LDObserve.RecordLog(
"Checkout completed",
LDObserve.Severity.Info,
Severity.Info,
new Dictionary<string, object?>
{
{ "order_id", "ORD-9876" },
Expand All @@ -120,16 +124,44 @@ LDObserve.RecordLog(

Supported severity levels: `Trace`, `Debug`, `Info`, `Warn`, `Error`, `Fatal`.

##### Logs with Span Context

You can correlate logs with a specific span for distributed tracing by capturing and passing a `SpanContext`:

```csharp
var span = LDObserve.StartActiveSpan("checkout-flow");
var capturedContext = span.Context;
span.End();

await Task.Run(() =>
{
LDObserve.RecordLog(
"Checkout processed on background thread",
Severity.Warn,
new Dictionary<string, object?> { { "source", "background-task" } },
spanContext: capturedContext);
});
```

This is useful when a log is emitted on a different thread or after the span has ended, but you still want it associated with the original trace.

#### Errors

Use `RecordError` to capture error events. The optional second parameter provides the underlying cause:
Use `RecordError` to capture error events. You can pass an `Exception` object directly, or a message string with an optional cause:

```csharp
// From an exception (inner exceptions are captured automatically)
var exception = new Exception("Payment failed", new TimeoutException("Connection timed out"));
LDObserve.RecordError(exception);

// From a message string with optional cause
LDObserve.RecordError("Payment failed", "Timeout connecting to payment gateway.");
```

#### Traces

> For in-depth examples covering nested spans, error handling, manual context propagation, and more, see the [Distributed Tracing Guide](./docs/distributed-tracing.md).

Use `LDObserve` to create spans for tracing operations in your application. Spans are backed by [OpenTelemetry](https://opentelemetry.io/) and should be disposed when the operation completes.

Create spans to trace operations. The returned `TelemetrySpan` is disposable — wrap it in a `using` statement so it ends automatically:
Expand All @@ -138,6 +170,7 @@ Create spans to trace operations. The returned `TelemetrySpan` is disposable —
using var span = LDObserve.StartActiveSpan("api_request");
span.SetAttribute("endpoint", "/api/users");
span.SetAttribute("method", "GET");
span.AddEvent("cache.miss");
```

##### Nested Spans
Expand All @@ -152,10 +185,64 @@ using var grandchild = LDObserve.StartActiveSpan("ChargeCard");
await httpClient.PostAsync("https://api.example.com/charge", content);
```

##### Independent Root Spans

Use `StartRootSpan` to create spans that are independent of the current trace context. This is useful for sequential operations that should not be nested:

```csharp
using (var span1 = LDObserve.StartRootSpan("SequentialOperation1"))
{
span1.SetAttribute("sequence", "1");
}

using (var span2 = LDObserve.StartRootSpan("SequentialOperation2"))
{
span2.SetAttribute("sequence", "2");
}
```

##### Manual Span Lifecycle

You can also manage a span's lifecycle manually using `End()` and capture its `Context` for distributed tracing:

```csharp
var span = LDObserve.StartActiveSpan("my-operation");
span.SetAttribute("key", "value");
var capturedContext = span.Context;
span.End();
```

| Method | Description |
|---|---|
| `LDObserve.StartActiveSpan(name)` | Start a new active span that automatically nests under the current parent. Returns a disposable `TelemetrySpan`. |
| `LDObserve.StartActiveSpan(name, parentContext)` | Start a new active span with an explicit parent `SpanContext` (defaults to `SpanKind.Internal`). Use when `Activity.Current` is not propagated. |
| `LDObserve.StartActiveSpan(name, kind, parentContext)` | Same as above but with an explicit `SpanKind`. |
| `LDObserve.StartRootSpan(name)` | Start a new root span with no parent. Returns a disposable `TelemetrySpan`. |
| `span.SetAttribute(key, value)` | Set a key-value attribute on a span. |
| `span.AddEvent(name)` | Record a named event on a span. |
| `span.Context` | Capture the span's context for correlating logs or other operations across async boundaries. |
| `span.End()` | Manually end a span (alternatively, use a `using` statement). |

##### Using `System.Diagnostics.Activity`

If you prefer the native .NET `Activity` API over OpenTelemetry's `TelemetrySpan`, equivalent methods are available. Activities are nullable — `StartActivity` returns `null` before SDK initialization or when no listener is registered:

```csharp
using System.Diagnostics;

using var activity = LDObserve.StartActivity("api_request");
activity?.SetTag("endpoint", "/api/users");
activity?.SetTag("method", "GET");
activity?.AddEvent(new ActivityEvent("cache.miss"));

// Root activity (no parent), equivalent to StartRootSpan
using var root = LDObserve.StartRootActivity("independent-operation");
root?.SetTag("sequence", "1");

// Or get the ActivitySource directly for full control
var source = LDObserve.GetActivitySource();
using var custom = source.StartActivity("custom", ActivityKind.Client);
```

### Identifying Users

Expand Down
Loading
Loading