Code Examples

Practical examples for using the Datadog MAUI SDK in your applications.


Table of Contents


Basic Setup

Minimal Configuration

// MauiProgram.cs
using Datadog.Maui;

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp<App>()
            .UseDatadog(config =>
            {
                config.ClientToken = "YOUR_CLIENT_TOKEN";
                config.Environment = "production";
                config.ServiceName = "my-maui-app";
            });

        return builder.Build();
    }
}

Full Configuration

builder.UseDatadog(config =>
{
    // Required settings
    config.ClientToken = "YOUR_CLIENT_TOKEN";
    config.Environment = "production";
    config.ServiceName = "my-maui-app";
    config.Site = DatadogSite.US1;

    // Optional settings
    config.VerboseLogging = true;
    config.TrackingConsent = TrackingConsent.Granted;

    // Global tags
    config.GlobalTags["app_version"] = VersionTracking.CurrentVersion;
    config.GlobalTags["app_build"] = VersionTracking.CurrentBuild;
    config.GlobalTags["platform"] = DeviceInfo.Platform.ToString();
    config.GlobalTags["device_model"] = DeviceInfo.Model;

    // First-party hosts for distributed tracing
    config.FirstPartyHosts = new[]
    {
        "api.myapp.com",
        "backend.myapp.com"
    };

    // Enable RUM
    config.EnableRum(rum =>
    {
        rum.SetApplicationId("YOUR_APPLICATION_ID");
        rum.SetSessionSampleRate(100);
        rum.SetTelemetrySampleRate(20);
        rum.TrackViewsAutomatically(true);
        rum.TrackUserInteractions(true);     // Enables automatic tap/swipe tracking
        rum.TrackFrustrations(true);         // Tracks rage taps, error taps, dead clicks
        rum.TrackBackgroundEvents(false);    // Track events while app is backgrounded
        rum.SetFirstPartyHostsTracingSampleRate(20); // 20% tracing sample rate on first-party hosts
        rum.SetVitalsUpdateFrequency(VitalsUpdateFrequency.Average);
    });

    // Enable Logs
    config.EnableLogs(logs =>
    {
        logs.SetSampleRate(100);
        logs.EnableNetworkInfo(true);
        logs.BundleWithRum(true);
    });

    // Enable Tracing
    config.EnableTracing(tracing =>
    {
        tracing.SetSampleRate(100);
        tracing.EnableTraceIdGeneration(true);
    });
});

Logging Examples

Basic Logging

using Datadog.Maui;

public class ExampleService
{
    private readonly ILogger _logger = Logs.CreateLogger("example-service");

    public void DoWork()
    {
        _logger.Debug("Starting work");
        _logger.Info("Processing item");
        _logger.Warn("Low memory warning");
        _logger.Error("Operation failed");
        _logger.Critical("System failure");
    }
}

Logging with Context

public class PaymentService
{
    private readonly ILogger _logger = Logs.CreateLogger("payment");

    public async Task ProcessPayment(PaymentRequest request)
    {
        _logger.Info("Processing payment", new Dictionary<string, object>
        {
            { "payment_id", request.Id },
            { "amount", request.Amount },
            { "currency", request.Currency },
            { "payment_method", request.Method },
            { "customer_id", request.CustomerId }
        });

        try
        {
            await _paymentGateway.ChargeAsync(request);

            _logger.Info("Payment successful", new Dictionary<string, object>
            {
                { "payment_id", request.Id },
                { "transaction_id", response.TransactionId },
                { "duration_ms", stopwatch.ElapsedMilliseconds }
            });
        }
        catch (PaymentException ex)
        {
            _logger.Error("Payment failed", ex, new Dictionary<string, object>
            {
                { "payment_id", request.Id },
                { "error_code", ex.Code },
                { "retry_count", retryCount }
            });

            throw;
        }
    }
}

Component-Specific Loggers

public class Application
{
    // Create component-specific loggers
    private readonly ILogger _networkLogger = Logs.CreateLogger("network");
    private readonly ILogger _databaseLogger = Logs.CreateLogger("database");
    private readonly ILogger _authLogger = Logs.CreateLogger("authentication");
    private readonly ILogger _analyticsLogger = Logs.CreateLogger("analytics");

    public void Initialize()
    {
        // Add component-specific attributes
        _networkLogger.AddAttribute("component", "network");
        _networkLogger.AddTag("layer", "infrastructure");

        _databaseLogger.AddAttribute("component", "database");
        _databaseLogger.AddTag("layer", "data");

        _authLogger.AddAttribute("component", "auth");
        _authLogger.AddTag("layer", "security");
    }

    public async Task FetchData()
    {
        _networkLogger.Info("Fetching data from API");
        var data = await _apiClient.GetAsync("/data");

        _databaseLogger.Info("Caching data");
        await _cache.SetAsync("data", data);

        _analyticsLogger.Info("Data fetch completed", new Dictionary<string, object>
        {
            { "record_count", data.Count },
            { "cache_size_kb", data.Length / 1024 }
        });
    }
}

Global Logger Configuration

public class App : Application
{
    public App()
    {
        // Add global attributes to all logs
        Logs.AddAttribute("app_version", VersionTracking.CurrentVersion);
        Logs.AddAttribute("platform", DeviceInfo.Platform.ToString());
        Logs.AddAttribute("device_model", DeviceInfo.Model);

        // Add global tags
        Logs.AddTag("env", "production");
        Logs.AddTag("region", GetUserRegion());

        // Create logger
        var logger = Logs.CreateLogger("app");
        logger.Info("Application started");
    }
}

RUM Examples

Page View Tracking

public class HomePage : ContentPage
{
    private const string ViewKey = "home_page";

    public HomePage()
    {
        InitializeComponent();
    }

    protected override void OnAppearing()
    {
        base.OnAppearing();

        // Start tracking this view
        Rum.StartView(ViewKey, "Home Page", new Dictionary<string, object>
        {
            { "user_tier", GetUserTier() },
            { "feature_flags", GetEnabledFeatures() }
        });
    }

    protected override void OnDisappearing()
    {
        base.OnDisappearing();

        // Stop tracking this view
        Rum.StopView(ViewKey, new Dictionary<string, object>
        {
            { "session_duration_sec", GetSessionDuration() }
        });
    }
}

User Interaction Tracking

public class ProductPage : ContentPage
{
    private void OnAddToCartClicked(object sender, EventArgs e)
    {
        // Track user action
        Rum.AddAction(RumActionType.Tap, "add_to_cart", new Dictionary<string, object>
        {
            { "product_id", _product.Id },
            { "product_name", _product.Name },
            { "price", _product.Price },
            { "quantity", _quantityInput.Value }
        });

        AddToCart(_product);
    }

    private void OnProductImageTapped(object sender, EventArgs e)
    {
        Rum.AddAction(RumActionType.Tap, "view_product_image", new Dictionary<string, object>
        {
            { "product_id", _product.Id },
            { "image_index", GetImageIndex() }
        });

        ShowImageGallery();
    }

    private void OnScrolled(object sender, ScrolledEventArgs e)
    {
        // Track scroll depth for analytics
        var scrollPercent = (e.ScrollY / _scrollView.ContentSize.Height) * 100;

        if (scrollPercent > 75 && !_scrolledTo75)
        {
            _scrolledTo75 = true;
            Rum.AddAction(RumActionType.Scroll, "scrolled_75_percent", new Dictionary<string, object>
            {
                { "product_id", _product.Id }
            });
        }
    }
}

Network Request Tracking

public class ApiService
{
    private readonly HttpClient _httpClient;
    private readonly ILogger _logger = Logs.CreateLogger("api");

    public async Task<List<User>> FetchUsersAsync()
    {
        var resourceKey = $"fetch_users_{Guid.NewGuid()}";
        var url = "https://api.myapp.com/users";

        // Start tracking the resource
        Rum.StartResource(resourceKey, "GET", url);

        try
        {
            var stopwatch = Stopwatch.StartNew();
            var response = await _httpClient.GetAsync(url);
            stopwatch.Stop();

            var content = await response.Content.ReadAsStringAsync();

            // Stop tracking with success
            Rum.StopResource(
                resourceKey,
                statusCode: (int)response.StatusCode,
                size: content.Length,
                kind: RumResourceKind.Xhr,
                attributes: new Dictionary<string, object>
                {
                    { "duration_ms", stopwatch.ElapsedMilliseconds },
                    { "cache_hit", response.Headers.Contains("X-Cache-Hit") }
                }
            );

            return JsonSerializer.Deserialize<List<User>>(content);
        }
        catch (Exception ex)
        {
            _logger.Error("Failed to fetch users", ex);

            // Stop tracking with error
            Rum.StopResourceWithError(resourceKey, ex, new Dictionary<string, object>
            {
                { "retry_count", GetRetryCount() }
            });

            throw;
        }
    }
}

Error Tracking

public class ExampleViewModel
{
    public async Task LoadDataAsync()
    {
        try
        {
            await FetchData();
        }
        catch (NetworkException ex)
        {
            // Track network error
            Rum.AddError(ex, RumErrorSource.Network, new Dictionary<string, object>
            {
                { "endpoint", ex.Endpoint },
                { "status_code", ex.StatusCode },
                { "retry_count", _retryCount }
            });

            ShowErrorMessage("Network error. Please check your connection.");
        }
        catch (ValidationException ex)
        {
            // Track validation error
            Rum.AddError(ex, RumErrorSource.Source, new Dictionary<string, object>
            {
                { "field", ex.FieldName },
                { "validation_rule", ex.Rule }
            });

            ShowErrorMessage($"Invalid {ex.FieldName}");
        }
        catch (Exception ex)
        {
            // Track general error
            Rum.AddError(ex, RumErrorSource.Source);

            ShowErrorMessage("An unexpected error occurred");
        }
    }
}

Custom Performance Timings

public class CheckoutPage : ContentPage
{
    private const string ViewKey = "checkout_page";

    protected override async void OnAppearing()
    {
        base.OnAppearing();

        Rum.StartView(ViewKey, "Checkout");

        // Load payment methods
        await LoadPaymentMethods();
        Rum.AddTiming("payment_methods_loaded");

        // Load shipping options
        await LoadShippingOptions();
        Rum.AddTiming("shipping_options_loaded");

        // Load order summary
        await LoadOrderSummary();
        Rum.AddTiming("order_summary_loaded");

        // All data loaded
        Rum.AddTiming("checkout_ready");
    }

    private async Task ProcessCheckoutAsync()
    {
        Rum.AddTiming("checkout_started");

        await ValidatePayment();
        Rum.AddTiming("payment_validated");

        await ProcessOrder();
        Rum.AddTiming("order_processed");

        await SendConfirmationEmail();
        Rum.AddTiming("confirmation_sent");

        Rum.AddTiming("checkout_completed");
    }
}

Tracing Examples

Basic Tracing

public class DataService
{
    public async Task<Data> FetchAndProcessDataAsync()
    {
        // Start a span
        using (var span = Tracer.StartSpan("fetch_and_process"))
        {
            span.SetTag("operation_type", "data_processing");

            try
            {
                var data = await FetchDataAsync();
                var processed = ProcessData(data);

                span.SetTag("record_count", processed.Count);

                return processed;
            }
            catch (Exception ex)
            {
                span.SetError(ex);
                throw;
            }
            // Span automatically finishes when disposed
        }
    }
}

Nested Spans

public class OrderService
{
    public async Task ProcessOrderAsync(Order order)
    {
        // Parent span
        using (var parentSpan = Tracer.StartSpan("process_order"))
        {
            parentSpan.SetTag("order_id", order.Id);
            parentSpan.SetTag("customer_id", order.CustomerId);

            // Child span - validate
            using (var validateSpan = Tracer.StartSpan("validate_order", parentSpan))
            {
                validateSpan.SetTag("item_count", order.Items.Count);
                await ValidateOrder(order);
            }

            // Child span - payment
            using (var paymentSpan = Tracer.StartSpan("process_payment", parentSpan))
            {
                paymentSpan.SetTag("amount", order.TotalAmount);
                paymentSpan.SetTag("payment_method", order.PaymentMethod);

                try
                {
                    await ProcessPayment(order);
                }
                catch (PaymentException ex)
                {
                    paymentSpan.SetError(ex);
                    throw;
                }
            }

            // Child span - inventory
            using (var inventorySpan = Tracer.StartSpan("update_inventory", parentSpan))
            {
                await UpdateInventory(order);
            }

            // Child span - notification
            using (var notifySpan = Tracer.StartSpan("send_notification", parentSpan))
            {
                await SendOrderConfirmation(order);
            }

            parentSpan.SetTag("status", "completed");
        }
    }
}

HTTP Client with Tracing

public class TracedHttpClient
{
    private readonly HttpClient _httpClient;

    public async Task<T> GetAsync<T>(string url)
    {
        using (var span = Tracer.StartSpan("http.request"))
        {
            span.SetTag("http.method", "GET");
            span.SetTag("http.url", url);

            var request = new HttpRequestMessage(HttpMethod.Get, url);

            // Inject trace context into request headers
            Tracer.Inject(request.Headers, span);

            try
            {
                var response = await _httpClient.SendAsync(request);

                span.SetTag("http.status_code", (int)response.StatusCode);
                span.SetTag("http.response_size", response.Content.Headers.ContentLength ?? 0);

                response.EnsureSuccessStatusCode();

                var content = await response.Content.ReadAsStringAsync();
                return JsonSerializer.Deserialize<T>(content);
            }
            catch (HttpRequestException ex)
            {
                span.SetError(ex);
                span.SetTag("error", true);
                throw;
            }
        }
    }
}

Trace Extraction (Server-Side)

public class ApiController
{
    [HttpGet("data")]
    public async Task<IActionResult> GetData()
    {
        // Extract trace context from incoming request
        var headers = Request.Headers.ToDictionary(h => h.Key, h => h.Value.FirstOrDefault());
        var parentSpan = Tracer.Extract(headers);

        // Continue the trace
        using (var span = Tracer.StartSpan("api.get_data", parentSpan))
        {
            span.SetTag("endpoint", "/data");
            span.SetTag("user_id", GetUserId());

            var data = await _dataService.FetchDataAsync();

            span.SetTag("record_count", data.Count);

            return Ok(data);
        }
    }
}

Span Events

public class CacheService
{
    public async Task<Data> GetDataAsync(string key)
    {
        using (var span = Tracer.StartSpan("cache.get"))
        {
            span.SetTag("cache_key", key);

            // Check cache
            var cached = await _cache.GetAsync(key);

            if (cached != null)
            {
                span.AddEvent("cache_hit", new Dictionary<string, object>
                {
                    { "cache_age_seconds", GetCacheAge(cached) }
                });

                return cached;
            }

            span.AddEvent("cache_miss");

            // Fetch from source
            var data = await _source.FetchAsync(key);

            span.AddEvent("fetched_from_source", new Dictionary<string, object>
            {
                { "data_size_bytes", data.Size }
            });

            // Update cache
            await _cache.SetAsync(key, data);

            span.AddEvent("cache_updated");

            return data;
        }
    }
}

Real-World Scenarios

E-Commerce Checkout Flow

public class CheckoutService
{
    private readonly ILogger _logger = Logs.CreateLogger("checkout");

    public async Task<CheckoutResult> ProcessCheckoutAsync(Cart cart)
    {
        // Start trace
        using (var checkoutSpan = Tracer.StartSpan("checkout.process"))
        {
            checkoutSpan.SetTag("cart_id", cart.Id);
            checkoutSpan.SetTag("item_count", cart.Items.Count);
            checkoutSpan.SetTag("total_amount", cart.TotalAmount);

            // Start RUM view
            Rum.StartView("checkout", "Checkout");

            try
            {
                // Step 1: Validate cart
                _logger.Info("Validating cart");
                using (var validateSpan = Tracer.StartSpan("checkout.validate", checkoutSpan))
                {
                    await ValidateCart(cart);
                }
                Rum.AddTiming("cart_validated");

                // Step 2: Process payment
                _logger.Info("Processing payment", new Dictionary<string, object>
                {
                    { "amount", cart.TotalAmount },
                    { "method", cart.PaymentMethod }
                });

                using (var paymentSpan = Tracer.StartSpan("checkout.payment", checkoutSpan))
                {
                    paymentSpan.SetTag("payment_method", cart.PaymentMethod);

                    try
                    {
                        await ProcessPayment(cart);
                        Rum.AddAction(RumActionType.Custom, "payment_successful");
                    }
                    catch (PaymentException ex)
                    {
                        paymentSpan.SetError(ex);
                        Rum.AddError(ex, RumErrorSource.Source, new Dictionary<string, object>
                        {
                            { "payment_method", cart.PaymentMethod },
                            { "error_code", ex.Code }
                        });
                        throw;
                    }
                }
                Rum.AddTiming("payment_processed");

                // Step 3: Create order
                _logger.Info("Creating order");
                using (var orderSpan = Tracer.StartSpan("checkout.create_order", checkoutSpan))
                {
                    var order = await CreateOrder(cart);
                    orderSpan.SetTag("order_id", order.Id);
                    checkoutSpan.SetTag("order_id", order.Id);
                }
                Rum.AddTiming("order_created");

                // Step 4: Update inventory
                _logger.Info("Updating inventory");
                using (var inventorySpan = Tracer.StartSpan("checkout.update_inventory", checkoutSpan))
                {
                    await UpdateInventory(cart);
                }
                Rum.AddTiming("inventory_updated");

                // Step 5: Send confirmation
                _logger.Info("Sending confirmation");
                using (var notifySpan = Tracer.StartSpan("checkout.send_confirmation", checkoutSpan))
                {
                    await SendConfirmation(cart);
                }
                Rum.AddTiming("confirmation_sent");

                // Success
                checkoutSpan.SetTag("status", "success");
                Rum.AddAction(RumActionType.Custom, "checkout_completed", new Dictionary<string, object>
                {
                    { "total_amount", cart.TotalAmount },
                    { "item_count", cart.Items.Count }
                });

                _logger.Info("Checkout completed successfully");

                Rum.StopView("checkout");

                return CheckoutResult.Success;
            }
            catch (Exception ex)
            {
                checkoutSpan.SetError(ex);
                _logger.Error("Checkout failed", ex);
                Rum.AddError(ex);
                Rum.StopView("checkout");
                throw;
            }
        }
    }
}

Authentication Flow

public class AuthenticationService
{
    private readonly ILogger _logger = Logs.CreateLogger("auth");

    public async Task<AuthResult> LoginAsync(string username, string password)
    {
        using (var span = Tracer.StartSpan("auth.login"))
        {
            span.SetTag("username", username);
            span.SetTag("auth_method", "password");

            _logger.Info("Login attempt", new Dictionary<string, object>
            {
                { "username", username }
            });

            Rum.StartView("login", "Login");

            try
            {
                // Validate credentials
                using (var validateSpan = Tracer.StartSpan("auth.validate_credentials", span))
                {
                    var user = await ValidateCredentials(username, password);

                    if (user == null)
                    {
                        _logger.Warn("Invalid credentials", new Dictionary<string, object>
                        {
                            { "username", username }
                        });

                        Rum.AddError("Invalid credentials", RumErrorSource.Source);
                        Rum.AddAction(RumActionType.Custom, "login_failed");

                        return AuthResult.InvalidCredentials;
                    }

                    validateSpan.SetTag("user_id", user.Id);
                    span.SetTag("user_id", user.Id);
                }

                // Create session
                using (var sessionSpan = Tracer.StartSpan("auth.create_session", span))
                {
                    var session = await CreateSession(user);
                    sessionSpan.SetTag("session_id", session.Id);
                }

                // Set user info in Datadog
                Datadog.SetUser(new UserInfo
                {
                    Id = user.Id,
                    Name = user.Name,
                    Email = user.Email,
                    ExtraInfo = new Dictionary<string, object>
                    {
                        { "account_type", user.AccountType },
                        { "signup_date", user.SignupDate }
                    }
                });

                _logger.Info("Login successful", new Dictionary<string, object>
                {
                    { "user_id", user.Id }
                });

                Rum.AddAction(RumActionType.Custom, "login_successful");
                Rum.StopView("login");

                return AuthResult.Success;
            }
            catch (Exception ex)
            {
                span.SetError(ex);
                _logger.Error("Login error", ex);
                Rum.AddError(ex);
                Rum.StopView("login");
                throw;
            }
        }
    }

    public void Logout()
    {
        _logger.Info("User logged out");
        Rum.AddAction(RumActionType.Custom, "logout");

        // Clear user info
        Datadog.ClearUser();
    }
}

Background Task with Monitoring

public class DataSyncService
{
    private readonly ILogger _logger = Logs.CreateLogger("data-sync");

    public async Task SyncDataAsync()
    {
        using (var span = Tracer.StartSpan("data_sync.full"))
        {
            _logger.Info("Starting data sync");

            try
            {
                // Fetch updates from server
                using (var fetchSpan = Tracer.StartSpan("data_sync.fetch", span))
                {
                    var updates = await FetchUpdatesFromServer();
                    fetchSpan.SetTag("update_count", updates.Count);

                    _logger.Info("Fetched updates", new Dictionary<string, object>
                    {
                        { "count", updates.Count },
                        { "size_kb", CalculateSize(updates) / 1024 }
                    });
                }

                // Apply updates locally
                using (var applySpan = Tracer.StartSpan("data_sync.apply", span))
                {
                    var applied = await ApplyUpdates(updates);
                    applySpan.SetTag("applied_count", applied);

                    _logger.Info("Applied updates", new Dictionary<string, object>
                    {
                        { "count", applied }
                    });
                }

                // Upload pending changes
                using (var uploadSpan = Tracer.StartSpan("data_sync.upload", span))
                {
                    var pending = await GetPendingChanges();
                    await UploadChanges(pending);
                    uploadSpan.SetTag("uploaded_count", pending.Count);

                    _logger.Info("Uploaded changes", new Dictionary<string, object>
                    {
                        { "count", pending.Count }
                    });
                }

                span.SetTag("status", "success");
                _logger.Info("Data sync completed successfully");
            }
            catch (Exception ex)
            {
                span.SetError(ex);
                _logger.Error("Data sync failed", ex);
                throw;
            }
        }
    }
}

MAUI Integration

MVVM Pattern

public class ProductViewModel : INotifyPropertyChanged
{
    private readonly ILogger _logger = Logs.CreateLogger("product-view-model");
    private readonly IProductService _productService;

    public ObservableCollection<Product> Products { get; } = new();

    public ICommand LoadProductsCommand { get; }
    public ICommand AddToCartCommand { get; }

    public ProductViewModel(IProductService productService)
    {
        _productService = productService;

        LoadProductsCommand = new Command(async () => await LoadProductsAsync());
        AddToCartCommand = new Command<Product>(async (product) => await AddToCartAsync(product));
    }

    private async Task LoadProductsAsync()
    {
        using (var span = Tracer.StartSpan("products.load"))
        {
            try
            {
                _logger.Info("Loading products");

                var products = await _productService.GetProductsAsync();

                Products.Clear();
                foreach (var product in products)
                {
                    Products.Add(product);
                }

                span.SetTag("product_count", products.Count);

                _logger.Info("Products loaded", new Dictionary<string, object>
                {
                    { "count", products.Count }
                });

                Rum.AddAction(RumActionType.Custom, "products_loaded", new Dictionary<string, object>
                {
                    { "count", products.Count }
                });
            }
            catch (Exception ex)
            {
                span.SetError(ex);
                _logger.Error("Failed to load products", ex);
                Rum.AddError(ex);
            }
        }
    }

    private async Task AddToCartAsync(Product product)
    {
        _logger.Info("Adding product to cart", new Dictionary<string, object>
        {
            { "product_id", product.Id },
            { "product_name", product.Name }
        });

        Rum.AddAction(RumActionType.Custom, "add_to_cart", new Dictionary<string, object>
        {
            { "product_id", product.Id },
            { "price", product.Price }
        });

        await _cartService.AddAsync(product);
    }
}

Dependency Injection

// MauiProgram.cs
public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();

        builder
            .UseMauiApp<App>()
            .UseDatadog(config => { /* ... */ });

        // Register Datadog interfaces for DI
        builder.Services.AddSingleton<IDatadogSdk>(DatadogSdk.Instance);
        builder.Services.AddSingleton<IDatadogLogger>(DatadogSdk.Logger);
        builder.Services.AddSingleton<IDatadogRum>(DatadogSdk.Rum);
        builder.Services.AddSingleton<IDatadogTrace>(DatadogSdk.Trace);

        // Register your services
        builder.Services.AddSingleton<IApiService, ApiService>();
        builder.Services.AddTransient<ProductViewModel>();

        return builder.Build();
    }
}

// Using in a service
public class ApiService : IApiService
{
    private readonly IDatadogLogger _logger;
    private readonly IDatadogTrace _tracer;

    public ApiService(IDatadogLogger logger, IDatadogTrace tracer)
    {
        _logger = logger;
        _tracer = tracer;
    }

    public async Task<Data> FetchDataAsync()
    {
        _logger.Info("Fetching data");
        using (var span = _tracer.StartSpan("api.fetch_data"))
        {
            // ...
        }
    }
}

See Also


Table of contents