Docs » Splunk Observability Cloud 用のサーバーレス関数を実装する » Splunk Observability Cloud 用 .NET Azure 関数をインストルメンテーションする

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

.NET Azure 関数をインストルメンテーションすることで、関数が実行されるたびに Splunk Observability Cloud にスパンを送信できます。孤立したワーカープロセスとプロセス内関数の両方をインストルメンテーションできます。

テレメトリを Splunk Observability Cloud に送信するために、.NET Azure 関数を OpenTelemetry でインストルメンテーションするには、以下のハイレベルな手順に従ってください:

注釈

SignalFx C# Azure Function ラッパーは非推奨です。Azure関数のインストルメンテーションには、以下のメソッドを使用してください。

環境変数の定義 🔗

関数の設定で必要な環境変数を設定します:

  1. 関数アプリで関数を選択します。

  2. Settings にアクセスし、次に Configuration にアクセスします。

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

    Name

    SPLUNK_ACCESS_TOKEN

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

    SPLUNK_REALM

    Splunk Observability Cloud レルム、たとえば us0 です。Splunk レルムを見つけるには、レルムに関する注意 を参照してください。

  4. その他必要な設定を追加します。

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

Visual StudioのNuGetを使って以下のライブラリを追加します:

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

  1. Include prerelease 設定を有効にします。

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

インプロセス機能 🔗

  1. Include prerelease 設定を有効にします。

  2. 以下のライブラリの指定されたバージョンをインストールします:

注釈

実行時の依存関係があるため、プロセス内関数のインストルメンテーションでは、指定されたバージョンのみが動作することが保証されています。

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

依存関係を追加したら、関数内で OpenTelemetry を初期化します。

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

Program.csファイルにスタートアップ初期化を追加します:

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using OpenTelemetry;
using OpenTelemetry.Exporter;
using OpenTelemetry.ResourceDetectors.Azure;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
using System.Diagnostics;

// 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 accessToken = Environment.GetEnvironmentVariable("SPLUNK_ACCESS_TOKEN")?.Trim();
var realm = Environment.GetEnvironmentVariable("SPLUNK_REALM")?.Trim();

ArgumentNullException.ThrowIfNull(accessToken, "SPLUNK_ACCESS_TOKEN");
ArgumentNullException.ThrowIfNull(realm, "SPLUNK_REALM");

var tp = Sdk.CreateTracerProviderBuilder()
   // 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")
   // Creates root spans for function executions
   .AddSource("Microsoft.Azure.Functions.Worker")
   .SetSampler(new AlwaysOnSampler())
   .ConfigureResource(configure => configure
      .AddService(serviceName: serviceName, serviceVersion: "1.0.0")
      // See https://github.com/open-telemetry/opentelemetry-dotnet-contrib/tree/main/src/OpenTelemetry.ResourceDetectors.Azure
      // for other types of Azure detectors
      .AddDetector(new AppServiceResourceDetector()))
   .AddOtlpExporter(opts =>
   {
      opts.Endpoint = new Uri($"https://ingest.{realm}.signalfx.com/v2/trace/otlp");
      opts.Protocol = OtlpExportProtocol.HttpProtobuf;
      opts.Headers = $"X-SF-TOKEN={accessToken}";
   })
   .Build();

var host = new HostBuilder()
   .ConfigureFunctionsWorkerDefaults()
   .ConfigureServices(services => services.AddSingleton(tp))
   .Build();

host.Run();

注釈

分離されたワーカープロセス関数をインストルメンテーションする場合、起動時の初期化やパラメータを他の関数にカプセル化することができます。

インプロセス機能 🔗

スタートアップ関数を定義し、その関数でアセンブリを装飾します。スタートアップ関数は、Azure.Functions.Extensions パッケージを使用して有用なメタデータを収集します。

using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using OpenTelemetry;
using OpenTelemetry.Exporter;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
using System;
using System.Collections.Generic;

// Decorate assembly with startup function
[assembly: FunctionsStartup(typeof(OtelManualExample.Startup))]

namespace OtelManualExample
{
   public class Startup : FunctionsStartup
   {
      public override void Configure(IFunctionsHostBuilder 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 accessToken = Environment.GetEnvironmentVariable("SPLUNK_ACCESS_TOKEN")?.Trim();
         var realm = Environment.GetEnvironmentVariable("SPLUNK_REALM")?.Trim();

         ArgumentNullException.ThrowIfNull(accessToken, "SPLUNK_ACCESS_TOKEN");
         ArgumentNullException.ThrowIfNull(realm, "SPLUNK_REALM");

         var tp = Sdk.CreateTracerProviderBuilder()
            // 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.Filter = req => Activity.Current?.Parent != null)
            .AddAspNetCoreInstrumentation()
            // Use AddSource to add your custom DiagnosticSource source names
            //.AddSource("My.Source.Name")
            .SetSampler(new AlwaysOnSampler())
            // Add resource attributes to all spans
            .SetResourceBuilder(
               ResourceBuilder.CreateDefault()
               .AddService(serviceName: serviceName, serviceVersion: "1.0.0")
               .AddAttributes(new Dictionary<string, object>() {
                  { "faas.instance", Environment.GetEnvironmentVariable("WEBSITE_INSTANCE_ID") }
               }))
            .AddOtlpExporter(opts =>
            {
               opts.Endpoint = new Uri($"https://ingest.{realm}.signalfx.com/v2/trace/otlp");
               opts.Protocol = OtlpExportProtocol.HttpProtobuf;
               opts.Headers = $"X-SF-TOKEN={accessToken}";
            })
            .Build();

         builder.Services.AddSingleton(tp);
      }
   }

スパンを送信するコードをインストルメンテーションする 🔗

次に、OpenTelemetry を使ってコードをインストルメンテーションします。コードをインストルメンテーションするための出発点として、以下の例を使用してください。Azure 関数に環境変数を追加する手順については、Microsoft Azure ドキュメントの https://learn.microsoft.com/en-us/azure/azure-functions/functions-how-to-use-azure-function-app-settings を参照してください。

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

次の例では、startヘルパー関数とstopヘルパー関数を使ったインストルメンテーションの方法を示しています:

using System.Diagnostics;
using System.Net;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Extensions.Logging;

namespace OtelManualIsolatedExample
{
   public class ExampleFunction
   {
      private readonly ILogger _logger;

      public ExampleFunction(ILoggerFactory loggerFactory)
      {
            _logger = loggerFactory.CreateLogger<ExampleFunction>();
      }
// Define helper functions for manual instrumentation
      public static ActivitySource ManualInstrumentationSource = new ActivitySource("manualInstrumentation");
      public static Activity? StartActivity(HttpRequestData req, FunctionContext fc)
      {
// Retrieve resource attributes
            var answer = ManualInstrumentationSource.StartActivity(req.Method.ToUpper() + " " + req.Url.AbsolutePath, ActivityKind.Server);
            answer?.AddTag("http.url", req.Url);
            answer?.AddTag("faas.invocation_id", fc.InvocationId.ToString());
            answer?.AddTag("faas.name", Environment.GetEnvironmentVariable("WEBSITE_SITE_NAME") + "/" + fc.FunctionDefinition.Name);
            return answer;
      }
      public static HttpResponseData FinishActivity(HttpResponseData response, Activity? activity)
      {
            activity?.AddTag("http.status_code", ((int)response.StatusCode));
            return response;
      }

      [Function("ExampleFunction")]
// Add the FunctionContext parameter to capture per-invocation information
      public HttpResponseData Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req, FunctionContext fc)
      {
            using (var activity = StartActivity(req, fc))
            {
               var response = req.CreateResponse(HttpStatusCode.OK);
               response.Headers.Add("Content-Type", "text/plain; charset=utf-8");

               response.WriteString("The current time is " + DateTime.Now.ToLongTimeString());

               return FinishActivity(response, activity);
            }
      }
   }
}

インプロセス機能 🔗

次の例は、faas 属性を取得する方法を示しています:

public static class ExampleFunction
{
   [FunctionName("ExampleFunction")]
// Add the ExecutionContext parameter to capture per-invocation information
   public static async Task<IActionResult> Run(
         [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
         ILogger log, ExecutionContext context)
   {
// You can also factor this out into a helper method to use across all functions
         Activity.Current.AddTag("faas.invocation_id", context.InvocationId.ToString());
         Activity.Current.AddTag("faas.name", Environment.GetEnvironmentVariable("WEBSITE_SITE_NAME") + "/" + context.FunctionName);

         string responseMessage = "The current time is " + DateTime.Now.ToLongTimeString();
         return new OkObjectResult(responseMessage);
   }
}

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

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

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

次の画像は、孤立したワーカープロセス機能によって送信されたスパンを示しています。faas タグに注目してください:

孤立したワーカープロセス関数からのスパン詳細

インプロセス機能 🔗

次の画像は、インプロセス関数から送信されたスパンを示しています。faas タグに注目してください:

インプロセス関数からのスパンの詳細

トラブルシューティング 🔗

Splunk Observability Cloudをご利用のお客様で、Splunk Observability Cloudでデータを確認できない場合は、以下の方法でサポートを受けることができます。

Splunk Observability Cloudをご利用のお客様

見込み客および無料トライアルユーザー様

  • Splunk Answers のコミュニティサポートで質問し、回答を得る

  • Splunk #observability ユーザーグループの Slack チャンネルに参加して、世界中の顧客、パートナー、Splunk 社員とのコミュニケーションを図る。参加するには、Get Started with Splunk Community マニュアルの チャットグループ を参照してください。

This page was last updated on 2024年05月29日.