Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 7 additions & 0 deletions docs/release-notes/3.14.0.2.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ and the trim/AOT analyzers are on with the surface analysing clean.
`BuildNugets.sh`) no longer carries that repository's comments verbatim: each file now says
what is true *here* and marks itself as a keep-in-sync copy.

## Sample

`DatadogNet.WebViewTracking.Mac` joins the sample with a tracked `WKWebView` page — web view
tracking works on Catalyst exactly as on iOS — and a button makes an instrumented `NSUrlSession`
request through the generic `Enable<TDelegate>()`. The sample now exercises every package with a
callable API that works on Catalyst.

## net8 sunset

Stated policy, so the decision does not persist by inertia: the `net8.0-maccatalyst18.0` head is
Expand Down
1 change: 1 addition & 0 deletions samples/DatadogNet.Mac.Example/DatadogNetExample.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
<PackageReference Include="DatadogNet.RUM.Mac" Version="$(DatadogPackageVersion)" />
<PackageReference Include="DatadogNet.Logs.Mac" Version="$(DatadogPackageVersion)" />
<PackageReference Include="DatadogNet.Trace.Mac" Version="$(DatadogPackageVersion)" />
<PackageReference Include="DatadogNet.WebViewTracking.Mac" Version="$(DatadogPackageVersion)" />
<PackageReference Include="DatadogNet.CrashReporting.Mac" Version="$(DatadogPackageVersion)" />
</ItemGroup>

Expand Down
14 changes: 14 additions & 0 deletions samples/DatadogNet.Mac.Example/MainPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,20 @@

<BoxView HeightRequest="1" Color="LightGray" />

<Label Text="Automatic instrumentation" FontSize="18" FontAttributes="Bold" />

<Button Text="Make an instrumented URLSession request"
Clicked="OnInstrumentedRequest" />

<BoxView HeightRequest="1" Color="LightGray" />

<Label Text="Web view" FontSize="18" FontAttributes="Bold" />

<Button Text="Open a tracked web view"
Clicked="OnOpenWebView" />

<BoxView HeightRequest="1" Color="LightGray" />

<Label Text="Activity" FontSize="18" FontAttributes="Bold" />

<Label x:Name="ActivityLabel"
Expand Down
51 changes: 51 additions & 0 deletions samples/DatadogNet.Mac.Example/MainPage.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,26 @@
using DatadogCore;
using DatadogLogs;
using DatadogRUM;
using DatadogTrace;
using Foundation;
using ObjCRuntime;

namespace DatadogNetExample;

/// <summary>
/// The delegate class <see cref="DDURLSessionInstrumentation"/> is enabled for. Empty on purpose:
/// the SDK instruments the class itself, so a session created with an instance of it reports its
/// requests with no code in the delegate — this only adds a completion signal for the demo.
/// </summary>
[Register(nameof(SampleSessionDelegate))]
internal sealed class SampleSessionDelegate : NSUrlSessionDataDelegate
{
public TaskCompletionSource<NSError?> Completion { get; } = new();

public override void DidCompleteWithError(NSUrlSession session, NSUrlSessionTask task, NSError? error) =>
Completion.TrySetResult(error);
}

/// <summary>
/// Each button drives one part of the Datadog API. The <see cref="ActivityLabel"/> echoes what was
/// reported, so the sample is useful even without a Datadog account to send it to.
Expand Down Expand Up @@ -195,6 +212,40 @@ private void OnLogException(object? sender, EventArgs e)
}
}

private static bool urlSessionInstrumented;

private async void OnInstrumentedRequest(object? sender, EventArgs e)
{
// Enable must come before the session is created: the SDK instruments the *delegate
// class*, and a session built earlier keeps the uninstrumented one. Enabled once — the
// convenience Enable<TDelegate> resolves the class handle and registers it with the SDK;
// the raw equivalent takes a Class handle and a configuration object.
if (!urlSessionInstrumented)
{
DDURLSessionInstrumentation.Enable<SampleSessionDelegate>();
urlSessionInstrumented = true;
Record("URLSession instrumentation enabled for SampleSessionDelegate");
}

var sessionDelegate = new SampleSessionDelegate();
using var session = NSUrlSession.FromConfiguration(
NSUrlSessionConfiguration.DefaultSessionConfiguration, sessionDelegate, null);

// No Datadog code from here on - that is the point. The request is reported as a RUM
// resource (and traced on first-party hosts) because of the class instrumentation above.
var task = session.CreateDataTask(NSUrlRequest.FromUrl(NSUrl.FromString("https://example.com/")!));
task.Resume();

var error = await sessionDelegate.Completion.Task;

Record(error is null
? "instrumented request finished - reported as a RUM resource with no per-call code"
: $"instrumented request failed: {error.LocalizedDescription}");
}

private async void OnOpenWebView(object? sender, EventArgs e) =>
await Navigation.PushAsync(new WebViewPage());

private void Record(string message)
{
activity.Insert(0, $"{DateTime.Now:HH:mm:ss} {message}");
Expand Down
76 changes: 76 additions & 0 deletions samples/DatadogNet.Mac.Example/WebViewPage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
using DatadogWebViewTracking;
using Foundation;
using WebKit;

namespace DatadogNetExample;

/// <summary>
/// A page hosting a <c>WKWebView</c> with the Datadog bridge installed, through the raw
/// <c>DatadogNet.WebViewTracking.iOS</c> binding.
/// </summary>
/// <remarks>
/// For anything to actually cross the bridge, the page inside must run the Datadog Browser SDK
/// and its host must be on the allowlist — example.com does not, so what this page demonstrates
/// is the wiring: enable when the platform view exists, disable when it goes away (the bridge
/// holds a reference to the web view, so leaving it installed keeps the page alive).
/// </remarks>
public sealed class WebViewPage : ContentPage
{
private readonly WebView webView;

public WebViewPage()
{
Title = "Web view";

webView = new WebView { Source = "https://example.com/" };
webView.Loaded += OnWebViewLoaded;
webView.Unloaded += OnWebViewUnloaded;

var layout = new Grid
{
RowDefinitions =
[
new RowDefinition(GridLength.Auto),
new RowDefinition(GridLength.Star),
],
};

layout.Add(
new Label
{
Padding = 12,
FontSize = 13,
Text = "DDWebViewTracking is enabled on this WKWebView. A page running the "
+ "Datadog Browser SDK on an allowlisted host would report into the "
+ "surrounding native session; example.com does not, so the point here "
+ "is the wiring.",
},
0,
0);
layout.Add(webView, 0, 1);

Content = layout;
}

private void OnWebViewLoaded(object? sender, EventArgs e)
{
// MAUI's iOS handler exposes the platform view, which is a WKWebView subclass. The hosts
// allowlist is an NSSet in the raw binding, matched by suffix — and it is an allowlist
// because the bridge lets page JavaScript write into your RUM session.
if (webView.Handler?.PlatformView is WKWebView platform)
{
DDWebViewTracking.EnableWithWebView(
platform,
new NSSet<NSString>(new NSString("example.com")),
logsSampleRate: 100);
}
}

private void OnWebViewUnloaded(object? sender, EventArgs e)
{
if (webView.Handler?.PlatformView is WKWebView platform)
{
DDWebViewTracking.DisableWithWebView(platform);
}
}
}
Loading