Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(tsc-opentelemetry): add new span attributes #681

Merged
merged 3 commits into from
Nov 30, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public static IServiceCollection AddObservable(this IServiceCollection services,
Func<string>? otlpUrlConfigure = null,
bool isBlazor = false,
bool isInterruptSignalRTracing = true)
{
{
ArgumentNullException.ThrowIfNull(optionsConfigure);
var options = optionsConfigure();
var otlpUrl = otlpUrlConfigure?.Invoke() ?? string.Empty;
Expand All @@ -45,7 +45,6 @@ public static IServiceCollection AddObservable(this IServiceCollection services,
Uri? uri = null;
if (!string.IsNullOrEmpty(otlpUrl) && !Uri.TryCreate(otlpUrl, UriKind.Absolute, out uri))
throw new UriFormatException($"{nameof(otlpUrl)}:{otlpUrl} is invalid url");

services.AddOpenTelemetry()
.ConfigureResource(resource => resource.AddMasaService(option))
.AddMasaTracing(services, builder => builder.AddOtlpExporter(options => options.Endpoint = uri),
Expand All @@ -67,4 +66,9 @@ public static IServiceCollection AddObservable(this IServiceCollection services,

return services;
}

public static IApplicationBuilder UseMASAHttpReponseLog(IApplicationBuilder app)
{
return app.UseMiddleware<HttpResponseMiddleware>();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright (c) MASA Stack All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.

namespace Masa.Contrib.StackSdks.Tsc.OpenTelemetry;

internal class HttpResponseMiddleware
{
private readonly RequestDelegate _next;

public HttpResponseMiddleware(RequestDelegate next)
{
_next = next;
}

public async Task InvokeAsync(HttpContext httpContext)
{
var httpResponse = httpContext.Response;
using var ms = new MemoryStream();
var rawStream = httpResponse.Body;
httpResponse.Body = ms;
await _next(httpContext);
ms.Seek(0, SeekOrigin.Begin);
var responseResult = new StreamReader(ms).ReadToEnd();
ms.Seek(0, SeekOrigin.Begin);
ms.CopyTo(rawStream);
httpResponse.Body = rawStream;

if (httpResponse.StatusCode - 299 == 0 || httpResponse.StatusCode - 500 >= 0)
{
Activity.Current?.SetTag(OpenTelemetryAttributeName.Http.RESPONSE_CONTENT_BODY, responseResult);
}
else
{
OpenTelemetryInstrumentationOptions.Logger.LogInformation("response length: {length}, context: {context}", responseResult.Length, responseResult);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,13 @@ internal static class Http
/// custom attr
/// </summary>
public const string RESPONSE_CONTENT_BODY = "http.response_content_body";

/// <summary>
/// https://opentelemetry.io/docs/specs/semconv/http/http-spans/#common-attributes
/// </summary>
public const string REQUEST_USER_AGENT = "user_agent.original";

public const string REQUEST_AUTHORIZATION = "authorization";
}

/// <summary>
Expand Down Expand Up @@ -144,7 +151,7 @@ internal static class Service
public const string PROJECT_NAME = "service.project.name";

public const string LAYER = "service.layer";
}
}

internal static class ExceptionAttributeName
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,22 @@ public static Activity AddMasaSupplement(this Activity activity, HttpRequest htt
{
activity.SetTag(OpenTelemetryAttributeName.Http.FLAVOR, httpRequest.Protocol);
activity.SetTag(OpenTelemetryAttributeName.Http.SCHEME, httpRequest.Scheme);
activity.SetTag(OpenTelemetryAttributeName.Http.CLIENT_IP, httpRequest.HttpContext?.Connection?.RemoteIpAddress);
activity.SetTag(OpenTelemetryAttributeName.Http.REQUEST_CONTENT_LENGTH, httpRequest.ContentLength);
activity.SetTag(OpenTelemetryAttributeName.Http.REQUEST_CONTENT_TYPE, httpRequest.ContentType);
if (httpRequest.Headers != null)
{
activity.SetTag(OpenTelemetryAttributeName.Http.REQUEST_AUTHORIZATION, httpRequest.Headers.Authorization);
activity.SetTag(OpenTelemetryAttributeName.Http.REQUEST_USER_AGENT, httpRequest.Headers.UserAgent);
var realIP = httpRequest.Headers["X-Real-IP"].ToString();
realIP ??= httpRequest.HttpContext!.Connection.RemoteIpAddress!.ToString();
activity.SetTag(OpenTelemetryAttributeName.Http.CLIENT_IP, realIP);
}

if ((httpRequest.HttpContext.User?.Claims.Count() ?? 0) > 0)
{
activity.AddTag(OpenTelemetryAttributeName.EndUser.ID, httpRequest.HttpContext.User?.FindFirst("sub")?.Value ?? string.Empty);
activity.AddTag(OpenTelemetryAttributeName.EndUser.USER_NICK_NAME, httpRequest.HttpContext.User?.FindFirst("https://masastack.com/security/authentication/MasaNickName")?.Value ?? string.Empty);
}
if (httpRequest.Body != null)
{
if (!httpRequest.Body.CanSeek)
Expand All @@ -26,7 +39,11 @@ public static Activity AddMasaSupplement(this Activity activity, HttpRequestMess
{
activity.SetTag(OpenTelemetryAttributeName.Http.SCHEME, httpRequest.RequestUri?.Scheme);
activity.SetTag(OpenTelemetryAttributeName.Host.NAME, Dns.GetHostName());

if (httpRequest.Headers != null)
{
activity.SetTag(OpenTelemetryAttributeName.Http.REQUEST_AUTHORIZATION, httpRequest.Headers.Authorization);
activity.SetTag(OpenTelemetryAttributeName.Http.REQUEST_USER_AGENT, httpRequest.Headers.UserAgent);
}
if (httpRequest.Content != null)
{
SetActivityBody(activity,
Expand All @@ -48,7 +65,12 @@ public static Activity AddMasaSupplement(this Activity activity, HttpResponse ht
activity.AddTag(OpenTelemetryAttributeName.EndUser.ID, httpResponse.HttpContext.User?.FindFirst("sub")?.Value ?? string.Empty);
activity.AddTag(OpenTelemetryAttributeName.EndUser.USER_NICK_NAME, httpResponse.HttpContext.User?.FindFirst("https://masastack.com/security/authentication/MasaNickName")?.Value ?? string.Empty);
}

if (httpResponse.HttpContext.Request != null && httpResponse.HttpContext.Request.Headers != null)
{
var realIP = httpResponse.HttpContext.Request.Headers["X-Real-IP"].ToString();
realIP ??= httpResponse.HttpContext!.Connection.RemoteIpAddress!.ToString();
activity.SetTag(OpenTelemetryAttributeName.Http.CLIENT_IP, realIP);
}
return activity;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,16 @@ public class OpenTelemetryInstrumentationOptions
{
public OpenTelemetryInstrumentationOptions(IServiceProvider serviceProvider)
{
Logger ??= serviceProvider.GetRequiredService<ILogger<OpenTelemetryInstrumentationOptions>>();
if (Logger == null)
{
var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
Logger = loggerFactory.CreateLogger("Masa.Contrib.StackSdks.Tsc.OpenTelemetry");
}
}

private readonly static AspNetCoreInstrumentationHandler aspNetCoreInstrumentationHandler = new();
private readonly static HttpClientInstrumentHandler httpClientInstrumentHandler = new();

internal static ILogger Logger { get; private set; }
internal static long MaxBodySize { get; private set; } = 200 * 1 << 10;

Expand Down Expand Up @@ -50,6 +55,10 @@ public OpenTelemetryInstrumentationOptions(IServiceProvider serviceProvider)
options.ParseAndFormatRequest = true;
};

public Func<IConnectionMultiplexer> ConnectionMultiplexerOptions { get; set; }

public Action<StackExchangeRedisInstrumentationOptions> StackExchangeRedisInstrumentationOptions { get; set; }

/// <summary>
/// Build trace callback, allow to supplement the build process
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,31 @@
// Copyright (c) MASA Stack All rights reserved.
// Licensed under the Apache License. See LICENSE.txt in the project root for license information.

using StackExchange.Redis;

namespace Microsoft.Extensions.DependencyInjection;

public static partial class ServiceExtensions
{
public static IServiceCollection AddMasaTracing(this IServiceCollection services, Action<TracerProviderBuilder> builderConfigure, Action<OpenTelemetryInstrumentationOptions>? configure = null)
public static IServiceCollection AddMasaTracing(this IServiceCollection services,
Action<TracerProviderBuilder> builderConfigure,
Action<OpenTelemetryInstrumentationOptions>? configure = null)
{
services.AddOpenTelemetry().AddMasaTracing(services, builderConfigure, configure);
return services;
}

internal static OpenTelemetryBuilder AddMasaTracing(this OpenTelemetryBuilder builder, IServiceCollection services, Action<TracerProviderBuilder> builderConfigure, Action<OpenTelemetryInstrumentationOptions>? configure = null)
internal static OpenTelemetryBuilder AddMasaTracing(this OpenTelemetryBuilder builder,
IServiceCollection services,
Action<TracerProviderBuilder> builderConfigure,
Action<OpenTelemetryInstrumentationOptions>? openTelemetryInstrumentationOptions = null)
{
return builder.WithTracing(builder =>
{
builder.SetSampler(new AlwaysOnSampler());
var option = new OpenTelemetryInstrumentationOptions(services.BuildServiceProvider());
configure?.Invoke(option);
var option = services.BuildServiceProvider().GetService<OpenTelemetryInstrumentationOptions>();
option ??= new OpenTelemetryInstrumentationOptions(services.BuildServiceProvider());
openTelemetryInstrumentationOptions?.Invoke(option);

if (option.AspNetCoreInstrumentationOptions != null)
builder.AddAspNetCoreInstrumentation(option.AspNetCoreInstrumentationOptions);
Expand All @@ -31,6 +39,19 @@ internal static OpenTelemetryBuilder AddMasaTracing(this OpenTelemetryBuilder bu
if (option.ElasticsearchClientInstrumentationOptions != null)
builder.AddElasticsearchClientInstrumentation(option.ElasticsearchClientInstrumentationOptions);

if (option.ConnectionMultiplexerOptions != null)
{
foreach (Delegate handle in option.ConnectionMultiplexerOptions.GetInvocationList())
{
var obj = handle.DynamicInvoke();
builder.AddRedisInstrumentation((IConnectionMultiplexer)obj!, options =>
{
options.SetVerboseDatabaseStatements = true;
option.StackExchangeRedisInstrumentationOptions?.Invoke(options);
});
}
}

builderConfigure?.Invoke(builder);
option.BuildTraceCallback?.Invoke(builder);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
global using Masa.Contrib.StackSdks.Tsc.OpenTelemetry;
global using Masa.Contrib.StackSdks.Tsc.OpenTelemetry.Metric.Instrumentation.Http;
global using Masa.Contrib.StackSdks.Tsc.OpenTelemetry.Tracing.Handler;
global using Microsoft.AspNetCore.Builder;
global using Microsoft.AspNetCore.Http;
global using Microsoft.Extensions.Configuration;
global using Microsoft.Extensions.DependencyInjection;
Expand All @@ -14,10 +15,12 @@
global using OpenTelemetry.Instrumentation.ElasticsearchClient;
global using OpenTelemetry.Instrumentation.EntityFrameworkCore;
global using OpenTelemetry.Instrumentation.Http;
global using OpenTelemetry.Instrumentation.StackExchangeRedis;
global using OpenTelemetry.Logs;
global using OpenTelemetry.Metrics;
global using OpenTelemetry.Resources;
global using OpenTelemetry.Trace;
global using StackExchange.Redis;
global using System;
global using System.Collections.Generic;
global using System.Diagnostics;
Expand Down
Loading