Splunk Observability Cloud 用 .NET Azure WebJobs をインストルメンテーションする

OpenTelemetry .NET SDK を使用して、Azure WebJobs 上で実行されているアプリケーションまたはサービスをインストルメンテーションすることができます。開始するには、次の手順を実行します。

OpenTelemetry .NET SDK を使用して、Azure WebJobs 上で実行されているアプリケーションまたはサービスをインストルメンテーションすることができます。開始するには、次の手順を実行します。

環境変数の定義

アプリケーションに必要な環境変数を設定します。

  1. Azure Web App でアプリケーションを選択します。

  2. Settings > Configuration に進みます。

  3. New application setting を選択し、以下の設定を追加します:

    Name

    SPLUNK_ACCESS_TOKEN

    Splunk アクセストークン。アクセストークンを取得するには、「Splunk Observability Cloud を使用したユーザー API アクセストークンの取得と管理」を参照してください。

    SPLUNK_REALM

    Splunk Observability Cloud のレルム(us0 など)。レルムを見つけるには、「 Configure SSO integrations for Splunk Observability Cloud」を参照してください。

  4. その他必要な設定を追加します。「Splunk Distribution of OpenTelemetry .NET を設定する」を参照してください。

NuGetを使って必要なライブラリを追加する

Visual Studio の NuGet パッケージマネージャを使用して、以下のライブラリを追加します。

分離されたワーカープロセス機能

  1. Include prerelease 設定をアクティブ化します。

  2. 以下のライブラリの最新版をインストールします:

コード内でOpenTelemetryを初期化する

  1. 依存関係を追加したら、アプリケーション用の OpenTelemetry ヘルパーを作成します:
    using Microsoft.Azure.WebJobs;
    using Microsoft.Azure.WebJobs.Host;
    using Microsoft.Extensions.DependencyInjection;
    using OpenTelemetry.Exporter;
    using OpenTelemetry.Metrics;
    using OpenTelemetry.Resources;
    using OpenTelemetry.Trace;
    using System.Diagnostics;
    
    namespace <YourNamespaceHere>.Helpers;
    
    internal static class SplunkOpenTelemetry
    {
        private static readonly string AccessToken;
        private static readonly string Realm;
    
        static SplunkOpenTelemetry()
        {
            AccessToken = Environment.GetEnvironmentVariable("SPLUNK_ACCESS_TOKEN")?.Trim()
                ?? throw new ArgumentNullException("SPLUNK_ACCESS_TOKEN");
    
            Realm = Environment.GetEnvironmentVariable("SPLUNK_REALM")?.Trim()
                ?? throw new ArgumentNullException("SPLUNK_REALM");
        }
    
        public static IWebJobsBuilder AddSplunkOpenTelemetry(this IWebJobsBuilder builder)
        {
            // Get environment variables from function configuration
            // You need a valid Splunk Observability Cloud access token and realm
            var serviceName = Environment.GetEnvironmentVariable("WEBSITE_SITE_NAME") ?? "Unknown";
            var enableTraceResponseHeaderValue = Environment.GetEnvironmentVariable("SPLUNK_TRACE_RESPONSE_HEADER_ENABLED")?.Trim();
    
            builder.Services.AddOpenTelemetry()
                .ConfigureResource(cfg => cfg
                    // See https://github.com/open-telemetry/opentelemetry-dotnet-contrib/tree/main/src/OpenTelemetry.Resources.Azure
                    // for other types of Azure detectors
                    .AddAzureAppServiceDetector()
                    .AddService(serviceName: serviceName, serviceVersion: "1.0.0"))
                .WithTracing(t => t
                    // Use Add[instrumentation-name]Instrumentation to instrument missing services
                    // Use Nuget to find different instrumentation libraries
                    .AddHttpClientInstrumentation(opts =>
                    {
                        // This filter prevents background (parent-less) http client activity
                        opts.FilterHttpWebRequest = req => Activity.Current?.Parent != null;
                        opts.FilterHttpRequestMessage = req => Activity.Current?.Parent != null;
                    })
                    // Use AddSource to add your custom DiagnosticSource source names
                    //.AddSource("My.Source.Name")
                    // Automatically creates the root span with function start
                    .AddSource(SplunkFunctionAttribute.ActivitySourceName)
                    .SetSampler(new AlwaysOnSampler())
                    .AddOtlpExporter(opts =>
                    {
                        opts.Endpoint = new Uri($"https://ingest.{Realm}.signalfx.com/v2/trace/otlp");
                        opts.Protocol = OtlpExportProtocol.HttpProtobuf;
                        opts.Headers = $"X-SF-TOKEN={AccessToken}";
                    }))
                .WithMetrics(m => m
                    // Use Add[instrumentation-name]Instrumentation to instrument missing services
                    // Use Nuget to find different instrumentation libraries
                    .AddHttpClientInstrumentation()
                    .AddRuntimeInstrumentation()
                    .AddProcessInstrumentation()
                    .AddOtlpExporter(opts =>
                    {
                        opts.Endpoint = new Uri($"https://ingest.{Realm}.signalfx.com/v2/datapoint/otlp");
                        opts.Headers = $"X-SF-TOKEN={AccessToken}";
                    }));
    
            return builder;
        }
    }
    
    internal class SplunkFunctionAttribute : FunctionInvocationFilterAttribute
    {
        public const string ActivitySourceName = "Splunk.Azure.WebJob";
    
        private static readonly ActivitySource ActivitySource = new(ActivitySourceName);
    
        private Activity? _currentActivity;
    
        public override Task OnExecutingAsync(FunctionExecutingContext executingContext, CancellationToken cancellationToken)
        {
            _currentActivity = ActivitySource.StartActivity(executingContext.FunctionName, ActivityKind.Server);
            _currentActivity?.AddTag("faas.name", executingContext.FunctionName);
            _currentActivity?.AddTag("faas.instance", executingContext.FunctionInstanceId);
    
            return base.OnExecutingAsync(executingContext, cancellationToken);
        }
    
        public override Task OnExecutedAsync(FunctionExecutedContext executedContext, CancellationToken cancellationToken)
        {
            if (!executedContext.FunctionResult.Succeeded)
            {
                if (executedContext.FunctionResult.Exception != null)
                {
                    _currentActivity?.SetStatus(Status.Error.WithDescription(executedContext.FunctionResult.Exception.Message));
                    _currentActivity?.RecordException(executedContext.FunctionResult.Exception);
                }
                else
                {
                    _currentActivity?.SetStatus(Status.Error);
                }
            }
    
            _currentActivity?.Stop();
    
            return base.OnExecutedAsync(executedContext, cancellationToken);
        }
    }
  2. Program.cs ファイルで作成したヘルパーを使用します:
    var builder = new HostBuilder()
    .ConfigureWebJobs(context =>
    {
        context.AddSplunkOpenTelemetry();
    })
  3. SplunkFunctionAttribute は、定義されたすべての WebJobs 関数で使用します。関数に適切に属性を設定する方法の例を参照してください。
    public class Functions
    {
        [SplunkFunction]
        public void ProcessTimer([TimerTrigger("1/5 * * * * *")] TimerInfo timerInfo, ILogger logger)
        {
            logger.LogInformation("Hello World!");
        }
    }

データが入力されていることを確認する

関数を実行し、Splunk APM でスパンを検索します。詳細については、「トレース内でのスパンの表示およびフィルタリング」を参照してください。

トラブルシューティング

__ ___ ___ _ ______ _____________ _____ ________ ___ ___ ___ ____ __ ___ ____ ____ __ ______ _____________ ______ ___ ___ ___ ____ __ ___ _________ _____

_________ __ ______ _____________ _____ _________

_________ __ ___________ _________ ___ ____ _____ _____

  • ___ _ ________ ___ ___ _______ _______ _________ _______ __ ______ ________

  • ____ ___ ______ ______________ ____ _____ _____ _______ __ ___________ ____ __________ _________ ___ ______ _________ __________ __ _____ ___ ____ _______