Skip to content

Commit

Permalink
feat(tsc-opentelemetry): add new span attributes (#681)
Browse files Browse the repository at this point in the history
* feat: add new attributes: user_agent、authorization,client_ip and response body

* feat: add httpReponse middleware

* fix: update
  • Loading branch information
Qinyouzeng authored Nov 30, 2023
1 parent 0cd1946 commit ad9dc58
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 11 deletions.
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

0 comments on commit ad9dc58

Please sign in to comment.