/// <inheritdoc/> public override async Task <ExportResult> ExportAsync( IEnumerable <SpanData> spanDataList, CancellationToken cancellationToken) { var spanExportRequest = new OtlpCollector.ExportTraceServiceRequest(); spanExportRequest.ResourceSpans.AddRange(spanDataList.ToOtlpResourceSpans()); try { await this.traceClient.ExportAsync(spanExportRequest); } catch (RpcException ex) { ExporterEventSource.Log.FailedToReachCollector(ex); return(ExportResult.FailedRetryable); } return(ExportResult.Success); }
/// <inheritdoc/> public override async Task <ExportResult> ExportAsync( IEnumerable <Activity> activityBatch, CancellationToken cancellationToken) { var exporterRequest = new OtlpCollector.ExportTraceServiceRequest(); exporterRequest.ResourceSpans.AddRange(activityBatch.ToOtlpResourceSpans()); try { await this.traceClient.ExportAsync(exporterRequest, headers : this.headers, cancellationToken : cancellationToken); } catch (RpcException ex) { OpenTelemetryProtocolExporterEventSource.Log.FailedToReachCollector(ex); return(ExportResult.FailedRetryable); } return(ExportResult.Success); }
internal async Task <ExportResult> ExportAsync( IEnumerable <OtlpTrace.ResourceSpans> resourceSpansList, CancellationToken cancellationToken) { var spanExportRequest = new OtlpCollector.ExportTraceServiceRequest(); spanExportRequest.ResourceSpans.AddRange(resourceSpansList); try { await this.traceClient.ExportAsync(spanExportRequest, headers : this.headers, cancellationToken : cancellationToken); } catch (RpcException ex) { ExporterEventSource.Log.FailedToReachCollector(ex); return(ExportResult.FailedRetryable); } return(ExportResult.Success); }
internal static void AddBatch( this OtlpCollector.ExportTraceServiceRequest request, OtlpResource.Resource processResource, in Batch <Activity> activityBatch)
public void SendExportRequest_ExportTraceServiceRequest_SendsCorrectHttpRequest(bool includeServiceNameInResource) { // Arrange var evenTags = new[] { new KeyValuePair <string, object>("k0", "v0") }; var oddTags = new[] { new KeyValuePair <string, object>("k1", "v1") }; var sources = new[] { new ActivitySource("even", "2.4.6"), new ActivitySource("odd", "1.3.5"), }; var header1 = new { Name = "hdr1", Value = "val1" }; var header2 = new { Name = "hdr2", Value = "val2" }; var options = new OtlpExporterOptions { Endpoint = new Uri("http://localhost:4317"), Headers = $"{header1.Name}={header1.Value}, {header2.Name} = {header2.Value}", }; var httpHandlerMock = new Mock <HttpMessageHandler>(); HttpRequestMessage httpRequest = null; var httpRequestContent = Array.Empty <byte>(); httpHandlerMock.Protected() #if NET5_0_OR_GREATER .Setup <HttpResponseMessage>("Send", ItExpr.IsAny <HttpRequestMessage>(), ItExpr.IsAny <CancellationToken>()) .Returns((HttpRequestMessage request, CancellationToken token) => { return(new HttpResponseMessage()); }) .Callback <HttpRequestMessage, CancellationToken>((r, ct) => { httpRequest = r; // We have to capture content as it can't be accessed after request is disposed inside of SendExportRequest method httpRequestContent = r.Content.ReadAsByteArrayAsync()?.Result; }) #else .Setup <Task <HttpResponseMessage> >("SendAsync", ItExpr.IsAny <HttpRequestMessage>(), ItExpr.IsAny <CancellationToken>()) .ReturnsAsync((HttpRequestMessage request, CancellationToken token) => { return(new HttpResponseMessage()); }) .Callback <HttpRequestMessage, CancellationToken>(async(r, ct) => { httpRequest = r; // We have to capture content as it can't be accessed after request is disposed inside of SendExportRequest method httpRequestContent = await r.Content.ReadAsByteArrayAsync(); }) #endif .Verifiable(); var exportClient = new OtlpHttpTraceExportClient(options, new HttpClient(httpHandlerMock.Object)); var resourceBuilder = ResourceBuilder.CreateEmpty(); if (includeServiceNameInResource) { resourceBuilder.AddAttributes( new List <KeyValuePair <string, object> > { new KeyValuePair <string, object>(ResourceSemanticConventions.AttributeServiceName, "service_name"), new KeyValuePair <string, object>(ResourceSemanticConventions.AttributeServiceNamespace, "ns_1"), }); } var builder = Sdk.CreateTracerProviderBuilder() .SetResourceBuilder(resourceBuilder) .AddSource(sources[0].Name) .AddSource(sources[1].Name); using var openTelemetrySdk = builder.Build(); var processor = new BatchActivityExportProcessor(new TestExporter <Activity>(RunTest)); const int numOfSpans = 10; bool isEven; for (var i = 0; i < numOfSpans; i++) { isEven = i % 2 == 0; var source = sources[i % 2]; var activityKind = isEven ? ActivityKind.Client : ActivityKind.Server; var activityTags = isEven ? evenTags : oddTags; using Activity activity = source.StartActivity($"span-{i}", activityKind, parentContext: default, activityTags); processor.OnEnd(activity); } processor.Shutdown(); void RunTest(Batch <Activity> batch) { var request = new OtlpCollector.ExportTraceServiceRequest(); request.AddBatch(resourceBuilder.Build().ToOtlpResource(), batch); // Act var result = exportClient.SendExportRequest(request); // Assert Assert.True(result); Assert.NotNull(httpRequest); Assert.Equal(HttpMethod.Post, httpRequest.Method); Assert.Equal("http://localhost:4317/v1/traces", httpRequest.RequestUri.AbsoluteUri); Assert.Equal(2, httpRequest.Headers.Count()); Assert.Contains(httpRequest.Headers, h => h.Key == header1.Name && h.Value.First() == header1.Value); Assert.Contains(httpRequest.Headers, h => h.Key == header2.Name && h.Value.First() == header2.Value); Assert.NotNull(httpRequest.Content); Assert.IsType <OtlpHttpTraceExportClient.ExportRequestContent>(httpRequest.Content); Assert.Contains(httpRequest.Content.Headers, h => h.Key == "Content-Type" && h.Value.First() == OtlpHttpTraceExportClient.MediaContentType); var exportTraceRequest = OtlpCollector.ExportTraceServiceRequest.Parser.ParseFrom(httpRequestContent); Assert.NotNull(exportTraceRequest); Assert.Single(exportTraceRequest.ResourceSpans); var resourceSpan = exportTraceRequest.ResourceSpans.First(); if (includeServiceNameInResource) { Assert.Contains(resourceSpan.Resource.Attributes, (kvp) => kvp.Key == ResourceSemanticConventions.AttributeServiceName && kvp.Value.StringValue == "service_name"); Assert.Contains(resourceSpan.Resource.Attributes, (kvp) => kvp.Key == ResourceSemanticConventions.AttributeServiceNamespace && kvp.Value.StringValue == "ns_1"); } else { Assert.Contains(resourceSpan.Resource.Attributes, (kvp) => kvp.Key == ResourceSemanticConventions.AttributeServiceName && kvp.Value.ToString().Contains("unknown_service:")); } } }
internal static void AddBatch( this OtlpCollector.ExportTraceServiceRequest request, in Batch <Activity> activityBatch)
public OtlpCollector.ExportTraceServiceResponse Export(OtlpCollector.ExportTraceServiceRequest request, Metadata headers = null, DateTime?deadline = null, CancellationToken cancellationToken = default) { return(null); }
public void ToOtlpResourceSpansTest(bool addResource) { var evenTags = new[] { new KeyValuePair <string, object>("k0", "v0") }; var oddTags = new[] { new KeyValuePair <string, object>("k1", "v1") }; var sources = new[] { new ActivitySource("even", "2.4.6"), new ActivitySource("odd", "1.3.5"), }; using var exporter = new OtlpTraceExporter( new OtlpExporterOptions(), new NoopTraceServiceClient()); if (addResource) { exporter.SetResource( ResourceBuilder.CreateEmpty().AddAttributes( new List <KeyValuePair <string, object> > { new KeyValuePair <string, object>(Resources.ResourceSemanticConventions.AttributeServiceName, "service-name"), new KeyValuePair <string, object>(Resources.ResourceSemanticConventions.AttributeServiceNamespace, "ns1"), }).Build()); } else { exporter.SetResource(Resources.Resource.Empty); } var builder = Sdk.CreateTracerProviderBuilder() .AddSource(sources[0].Name) .AddSource(sources[1].Name); using var openTelemetrySdk = builder.Build(); var processor = new BatchActivityExportProcessor(new TestExporter <Activity>(RunTest)); const int numOfSpans = 10; bool isEven; for (var i = 0; i < numOfSpans; i++) { isEven = i % 2 == 0; var source = sources[i % 2]; var activityKind = isEven ? ActivityKind.Client : ActivityKind.Server; var activityTags = isEven ? evenTags : oddTags; using Activity activity = source.StartActivity($"span-{i}", activityKind, parentContext: default, activityTags); processor.OnEnd(activity); } processor.Shutdown(); void RunTest(Batch <Activity> batch) { var request = new OtlpCollector.ExportTraceServiceRequest(); request.AddBatch(exporter.ProcessResource, batch); Assert.Single(request.ResourceSpans); var oltpResource = request.ResourceSpans.First().Resource; if (addResource) { Assert.Contains(oltpResource.Attributes, (kvp) => kvp.Key == Resources.ResourceSemanticConventions.AttributeServiceName && kvp.Value.StringValue == "service-name"); Assert.Contains(oltpResource.Attributes, (kvp) => kvp.Key == Resources.ResourceSemanticConventions.AttributeServiceNamespace && kvp.Value.StringValue == "ns1"); } else { Assert.Contains(oltpResource.Attributes, (kvp) => kvp.Key == Resources.ResourceSemanticConventions.AttributeServiceName && kvp.Value.ToString().Contains("unknown_service:")); } foreach (var instrumentationLibrarySpans in request.ResourceSpans.First().InstrumentationLibrarySpans) { Assert.Equal(numOfSpans / 2, instrumentationLibrarySpans.Spans.Count); Assert.NotNull(instrumentationLibrarySpans.InstrumentationLibrary); var expectedSpanNames = new List <string>(); var start = instrumentationLibrarySpans.InstrumentationLibrary.Name == "even" ? 0 : 1; for (var i = start; i < numOfSpans; i += 2) { expectedSpanNames.Add($"span-{i}"); } var otlpSpans = instrumentationLibrarySpans.Spans; Assert.Equal(expectedSpanNames.Count, otlpSpans.Count); var kv0 = new OtlpCommon.KeyValue { Key = "k0", Value = new OtlpCommon.AnyValue { StringValue = "v0" } }; var kv1 = new OtlpCommon.KeyValue { Key = "k1", Value = new OtlpCommon.AnyValue { StringValue = "v1" } }; var expectedTag = instrumentationLibrarySpans.InstrumentationLibrary.Name == "even" ? kv0 : kv1; foreach (var otlpSpan in otlpSpans) { Assert.Contains(otlpSpan.Name, expectedSpanNames); Assert.Contains(expectedTag, otlpSpan.Attributes); } } } }
public ExportRequestContent(OtlpCollector.ExportTraceServiceRequest exportRequest) { this.exportRequest = exportRequest; this.Headers.ContentType = ProtobufMediaTypeHeader; }
public void ToOtlpResourceSpansTest() { var evenTags = new[] { new KeyValuePair <string, object>("k0", "v0") }; var oddTags = new[] { new KeyValuePair <string, object>("k1", "v1") }; var sources = new[] { new ActivitySource("even", "2.4.6"), new ActivitySource("odd", "1.3.5"), }; var resource = new Resources.Resource( new List <KeyValuePair <string, object> > { new KeyValuePair <string, object>(Resources.Resource.ServiceNamespaceKey, "ns1"), }); // This following is done just to set Resource to Activity. using var openTelemetrySdk = Sdk.CreateTracerProviderBuilder() .AddSource(sources[0].Name) .AddSource(sources[1].Name) .SetResource(resource) .Build(); var processor = new BatchExportProcessor <Activity>(new TestExporter <Activity>(RunTest)); const int numOfSpans = 10; bool isEven; for (var i = 0; i < numOfSpans; i++) { isEven = i % 2 == 0; var source = sources[i % 2]; var activityKind = isEven ? ActivityKind.Client : ActivityKind.Server; var activityTags = isEven ? evenTags : oddTags; using Activity activity = source.StartActivity($"span-{i}", activityKind, parentContext: default, activityTags); processor.OnEnd(activity); } processor.Shutdown(); void RunTest(Batch <Activity> batch) { var request = new OtlpCollector.ExportTraceServiceRequest(); request.AddBatch(batch); Assert.Single(request.ResourceSpans); var oltpResource = request.ResourceSpans.First().Resource; Assert.Equal(resource.Attributes.First().Key, oltpResource.Attributes.First().Key); Assert.Equal(resource.Attributes.First().Value, oltpResource.Attributes.First().Value.StringValue); foreach (var instrumentationLibrarySpans in request.ResourceSpans.First().InstrumentationLibrarySpans) { Assert.Equal(numOfSpans / 2, instrumentationLibrarySpans.Spans.Count); Assert.NotNull(instrumentationLibrarySpans.InstrumentationLibrary); var expectedSpanNames = new List <string>(); var start = instrumentationLibrarySpans.InstrumentationLibrary.Name == "even" ? 0 : 1; for (var i = start; i < numOfSpans; i += 2) { expectedSpanNames.Add($"span-{i}"); } var otlpSpans = instrumentationLibrarySpans.Spans; Assert.Equal(expectedSpanNames.Count, otlpSpans.Count); var kv0 = new OtlpCommon.KeyValue { Key = "k0", Value = new OtlpCommon.AnyValue { StringValue = "v0" } }; var kv1 = new OtlpCommon.KeyValue { Key = "k1", Value = new OtlpCommon.AnyValue { StringValue = "v1" } }; var expectedTag = instrumentationLibrarySpans.InstrumentationLibrary.Name == "even" ? kv0 : kv1; foreach (var otlpSpan in otlpSpans) { Assert.Contains(otlpSpan.Name, expectedSpanNames); Assert.Contains(expectedTag, otlpSpan.Attributes); } } } }