Splunk Observability Cloud 用 .NET Azure 関数をインストルメンテーションする 🔗
.NET Azure 関数をインストルメンテーションすることで、関数が実行されるたびに Splunk Observability Cloud にスパンを送信できます。孤立したワーカープロセスとプロセス内関数の両方をインストルメンテーションできます。
テレメトリを Splunk Observability Cloud に送信するために、.NET Azure 関数を OpenTelemetry でインストルメンテーションするには、以下のハイレベルな手順に従ってください:
注釈
SignalFx C# Azure Function ラッパーは非推奨です。Azure関数のインストルメンテーションには、以下のメソッドを使用してください。
環境変数の定義 🔗
関数の設定で必要な環境変数を設定します:
関数アプリで関数を選択します。
Settings にアクセスし、次に Configuration にアクセスします。
New application setting を選択し、以下の設定を追加します:
Name
値
SPLUNK_ACCESS_TOKEN
Splunk アクセストークン。アクセストークンを取得するには、Splunk Observability Cloudを使用したユーザー APIアクセストークンの取得と管理 を参照してください。
SPLUNK_REALM
Splunk Observability Cloud レルム、たとえば
us0
です。Splunk レルムを見つけるには、レルムに関する注意 を参照してください。その他必要な設定を追加します。
NuGetを使って必要なライブラリを追加する 🔗
Visual StudioのNuGetを使って以下のライブラリを追加します:
Include prerelease 設定を有効にします。
以下のライブラリの最新版をインストールします:
Include prerelease 設定を有効にします。
以下のライブラリの指定されたバージョンをインストールします:
注釈
実行時の依存関係があるため、プロセス内関数のインストルメンテーションでは、指定されたバージョンのみが動作することが保証されています。
Include prerelease 設定を有効にします。
以下のライブラリの指定されたバージョンをインストールします:
注釈
実行時の依存関係があるため、プロセス内関数のインストルメンテーションでは、指定されたバージョンのみが動作することが保証されています。
コード内で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);
}
}
}
スタートアップ関数を定義し、その関数でアセンブリを装飾します。スタートアップ関数は、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.FilterHttpRequestMessage = req => Activity.Current?.Parent != null;
opts.FilterHttpWebRequest = 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")
.AddAzureAppServiceDetector()
.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 で検索します。詳しくは トレース内でのスパンの表示およびフィルタリング を参照してください。
トラブルシューティング 🔗
Splunk Observability Cloudをご利用のお客様で、Splunk Observability Cloudでデータを確認できない場合は、以下の方法でサポートを受けることができます。
Splunk Observability Cloudをご利用のお客様
Submit a case in the Splunk Support Portal .
Contact Splunk Support .
見込み客および無料トライアルユーザー様
Splunk Answers のコミュニティサポートで質問し、回答を得る
Splunk #observability ユーザーグループの Slack チャンネルに参加して、世界中の顧客、パートナー、Splunk 社員とのコミュニケーションを図る。参加するには、Get Started with Splunk Community マニュアルの チャットグループ を参照してください。