forked from Cysharp/MagicOnion
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request Cysharp#422 from Cysharp/feat/opentelemetry_100rc11
feat: publish OpenTelemetry support to NuGet listed latest version.
- Loading branch information
Showing
18 changed files
with
674 additions
and
544 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
23 changes: 23 additions & 0 deletions
23
src/MagicOnion.Server.OpenTelemetry/Internal/MagicOnionInstrumentation.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
using System; | ||
using System.Reflection; | ||
|
||
namespace MagicOnion.Server.OpenTelemetry.Internal | ||
{ | ||
internal static class MagicOnionInstrumentation | ||
{ | ||
/// <summary> | ||
/// The assembly name. | ||
/// </summary> | ||
internal static readonly AssemblyName AssemblyName = typeof(MagicOnionInstrumentation).Assembly.GetName(); | ||
|
||
/// <summary> | ||
/// The activity source name. | ||
/// </summary> | ||
internal static readonly string ActivitySourceName = AssemblyName.Name; | ||
|
||
/// <summary> | ||
/// The version. | ||
/// </summary> | ||
internal static readonly Version Version = AssemblyName.Version; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
6 changes: 3 additions & 3 deletions
6
...elemetry/OpenTelemetrygRpcStatusHelper.cs → ...Telemetry/Internal/OpenTelemetryHelper.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
51 changes: 51 additions & 0 deletions
51
src/MagicOnion.Server.OpenTelemetry/Internal/PropagatorExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
using System.Diagnostics; | ||
using OpenTelemetry.Context.Propagation; | ||
using Grpc.Core; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using OpenTelemetry; | ||
|
||
// ReSharper disable once CheckNamespace | ||
|
||
namespace MagicOnion.Server.OpenTelemetry.Internal | ||
{ | ||
internal static class PropagatorExtensions | ||
{ | ||
/// <summary> | ||
/// Injects the context into a carrier | ||
/// </summary> | ||
/// <param name="propagator"></param> | ||
/// <param name="context"></param> | ||
/// <param name="carrier"></param> | ||
public static void Inject(this TextMapPropagator propagator, PropagationContext context, CallOptions carrier) | ||
{ | ||
static void SetMetadata(Metadata metadata, string key, string value) => metadata.Add(new Metadata.Entry(key, value)); | ||
propagator.Inject(context, carrier.Headers, SetMetadata); | ||
} | ||
|
||
/// <summary> | ||
/// Extract the context from a carrier | ||
/// </summary> | ||
/// <param name="propagator"></param> | ||
/// <param name="activityContext"></param> | ||
/// <param name="carrier"></param> | ||
/// <returns></returns> | ||
public static PropagationContext Extract(this TextMapPropagator propagator, ActivityContext? activityContext, Metadata carrier) | ||
{ | ||
static IEnumerable<string> GetMetadata(Metadata metadata, string key) | ||
{ | ||
for (var i = 0; i < metadata.Count; i++) | ||
{ | ||
var entry = metadata[i]; | ||
if (entry.Key.Equals(key)) | ||
{ | ||
return new string[1] { entry.Value }; | ||
} | ||
} | ||
|
||
return Enumerable.Empty<string>(); | ||
} | ||
return propagator.Extract(new PropagationContext(activityContext ?? default, Baggage.Current), carrier, GetMetadata); | ||
} | ||
} | ||
} |
31 changes: 31 additions & 0 deletions
31
src/MagicOnion.Server.OpenTelemetry/Internal/SemanticConventions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
namespace MagicOnion.Server.OpenTelemetry.Internal | ||
{ | ||
/// <summary> | ||
/// OpenTelemetry Tag Keys | ||
/// </summary> | ||
internal static class SemanticConventions | ||
{ | ||
// tag spec: https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/semantic_conventions/rpc.md#grpc | ||
public const string AttributeServiceName = "service.name"; | ||
public const string AttributeException = "exception"; | ||
|
||
public const string AttributeHttpHost = "http.host"; | ||
public const string AttributeHttpUrl = "http.url"; | ||
public const string AttributeHttpUserAgent = "http.user_agent"; | ||
|
||
public const string AttributeRpcGrpcMethod = "rpc.grpc.method"; | ||
public const string AttributeRpcGrpcStatusCode = "rpc.grpc.status_code"; | ||
public const string AttributeRpcGrpcStatusDetail = "rpc.grpc.status_detail"; | ||
public const string AttributeRpcSystem = "rpc.system"; | ||
public const string AttributeRpcService = "rpc.service"; | ||
public const string AttributeRpcMethod = "rpc.method"; | ||
|
||
public const string AttributeMessageId = "message.id"; | ||
public const string AttributeMessageCompressedSize = "message.compressed_size"; | ||
public const string AttributeMessageUncompressedSize = "message.uncompressed_size"; | ||
|
||
public const string AttributeMagicOnionPeerName = "magiconion.peer.ip"; | ||
public const string AttributeMagicOnionAuthEnabled = "magiconion.auth.enabled"; | ||
public const string AttributeMagicOnionAuthPeerAuthenticated = "magiconion.auth.peer_authenticated"; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
90 changes: 90 additions & 0 deletions
90
src/MagicOnion.Server.OpenTelemetry/MagicOnionOpenTelemetryClientFilter.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
using Grpc.Core; | ||
using MagicOnion.Client; | ||
using MagicOnion.Server.OpenTelemetry.Internal; | ||
using OpenTelemetry; | ||
using OpenTelemetry.Context.Propagation; | ||
using System; | ||
using System.Diagnostics; | ||
using System.Threading.Tasks; | ||
|
||
namespace MagicOnion.Server.OpenTelemetry | ||
{ | ||
// note: move package to MagicOnion.Client.OpenTelemetry? | ||
/// <summary> | ||
/// Collect OpenTelemetry Tracer with Client filter (Unary). | ||
/// </summary> | ||
public class MagicOnionOpenTelemetryClientFilter : IClientFilter | ||
{ | ||
readonly ActivitySource source; | ||
readonly MagicOnionOpenTelemetryOptions options; | ||
|
||
public MagicOnionOpenTelemetryClientFilter(ActivitySource activitySource, MagicOnionOpenTelemetryOptions options) | ||
{ | ||
this.source = activitySource; | ||
this.options = options; | ||
} | ||
|
||
public async ValueTask<ResponseContext> SendAsync(RequestContext context, Func<RequestContext, ValueTask<ResponseContext>> next) | ||
{ | ||
var rpcService = context.MethodPath.Split('/')[0]; | ||
using var rpcScope = new ClientRpcScope(rpcService, context.MethodPath, context, source, options); | ||
rpcScope.SetTags(options.TracingTags); | ||
|
||
try | ||
{ | ||
var response = await next(context); | ||
|
||
rpcScope.Complete(); | ||
return response; | ||
} | ||
catch (Exception ex) | ||
{ | ||
rpcScope.CompleteWithException(ex); | ||
throw; | ||
} | ||
finally | ||
{ | ||
rpcScope.RestoreParentActivity(); | ||
} | ||
} | ||
} | ||
|
||
internal class ClientRpcScope : RpcScope | ||
{ | ||
public ClientRpcScope(string rpcService, string rpcMethod, RequestContext context, ActivitySource source, MagicOnionOpenTelemetryOptions options) | ||
: base(rpcService, rpcMethod, options.ServiceName) | ||
{ | ||
// capture the current activity | ||
this.ParentActivity = Activity.Current; | ||
|
||
if (!source.HasListeners()) | ||
return; | ||
|
||
var rpcActivity = source.StartActivity( | ||
context.MethodPath.TrimStart('/'), | ||
ActivityKind.Client, | ||
ParentActivity == default ? default : ParentActivity.Context); | ||
|
||
if (rpcActivity == null) | ||
return; | ||
|
||
var callOptions = context.CallOptions; | ||
if (callOptions.Headers == null) | ||
{ | ||
callOptions = callOptions.WithHeaders(new Metadata()); | ||
} | ||
|
||
SetActivity(rpcActivity); | ||
|
||
Propagators.DefaultTextMapPropagator.Inject(new PropagationContext(rpcActivity.Context, Baggage.Current), callOptions); | ||
} | ||
|
||
/// <summary> | ||
/// Restores the parent activity. | ||
/// </summary> | ||
public void RestoreParentActivity() | ||
{ | ||
Activity.Current = this.ParentActivity; | ||
} | ||
} | ||
} |
41 changes: 12 additions & 29 deletions
41
src/MagicOnion.Server.OpenTelemetry/MagicOnionOpenTelemetryOption.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,43 +1,26 @@ | ||
using System; | ||
using System.Reflection; | ||
using OpenTelemetry.Metrics; | ||
using OpenTelemetry.Metrics.Export; | ||
using System.Collections.Generic; | ||
|
||
namespace MagicOnion.Server.OpenTelemetry | ||
{ | ||
/// <summary> | ||
/// OpenTelemetry Options to inject Application Information | ||
/// </summary> | ||
public class MagicOnionOpenTelemetryOptions | ||
{ | ||
/// <summary> | ||
/// Metrics Exporter Endpoint. Default Prometheus endpoint. | ||
/// ServiceName for Tracer. Especially Zipkin use service.name tag to identify service name. | ||
/// </summary> | ||
public string MetricsExporterEndpoint { get; set; } = "http://127.0.0.1:9184/metrics/"; | ||
/// <summary> | ||
/// Metrics Exporter Hosting Endpoint. | ||
/// </summary> | ||
public string MetricsExporterHostingEndpoint { get; set; } = "http://+:9184/metrics/"; | ||
/// <summary> | ||
/// Tracer ServiceName use as ActivitySource | ||
/// </summary> | ||
public string MagicOnionActivityName { get; set; } = Assembly.GetEntryAssembly().GetName().Name; | ||
} | ||
/// <remarks>input to tag `service.name`</remarks> | ||
public string ServiceName { get; set; } | ||
|
||
public class MagicOnionOpenTelemetryMeterFactoryOption | ||
{ | ||
/// <summary> | ||
/// OpenTelemetry MetricsProcessor. default is <see cref="UngroupedBatcher"/> | ||
/// Expose RpsScope to the ServiceContext.Items. RpsScope key begin with .TraceContext | ||
/// </summary> | ||
public MetricProcessor MetricProcessor { get; set; } = new UngroupedBatcher(); | ||
/// <summary> | ||
/// OpenTelemetry MetricsExporter Implementation to use. | ||
/// </summary> | ||
public MetricExporter MetricExporter { get; set; } | ||
/// <summary> | ||
/// OpenTelemetry Metric Push Interval. | ||
/// </summary> | ||
public TimeSpan MetricPushInterval { get; set; } = TimeSpan.FromSeconds(10); | ||
public bool ExposeRpcScope { get; set; } = true; | ||
|
||
/// <summary> | ||
/// MagicOnionLogger to collect OpenTelemetry metrics. | ||
/// Application specific OpenTelemetry Tracing tags | ||
/// </summary> | ||
public Func<MeterProvider, IMagicOnionLogger> MeterLogger { get; set; } | ||
public Dictionary<string, string> TracingTags { get; set; } = new Dictionary<string, string>(); | ||
} | ||
} |
Oops, something went wrong.