public void OtlpExporterOptions_SetterOverridesEnvironmentVariable() { Environment.SetEnvironmentVariable(OtlpExporterOptions.EndpointEnvVarName, "http://test:8888"); Environment.SetEnvironmentVariable(OtlpExporterOptions.HeadersEnvVarName, "A=2,B=3"); Environment.SetEnvironmentVariable(OtlpExporterOptions.TimeoutEnvVarName, "2000"); Environment.SetEnvironmentVariable(OtlpExporterOptions.ProtocolEnvVarName, "grpc"); var options = new OtlpExporterOptions { Endpoint = new Uri("http://localhost:200"), Headers = "C=3", TimeoutMilliseconds = 40000, Protocol = OtlpExportProtocol.HttpProtobuf, }; Assert.Equal(new Uri("http://localhost:200"), options.Endpoint); Assert.Equal("C=3", options.Headers); Assert.Equal(40000, options.TimeoutMilliseconds); Assert.Equal(OtlpExportProtocol.HttpProtobuf, options.Protocol); }
public void GlobalSetup() { var mockClient = new Mock <OtlpCollector.TraceService.TraceServiceClient>(); mockClient .Setup(m => m.Export( It.IsAny <OtlpCollector.ExportTraceServiceRequest>(), It.IsAny <Metadata>(), It.IsAny <DateTime?>(), It.IsAny <CancellationToken>())) .Returns(new OtlpCollector.ExportTraceServiceResponse()); var options = new OtlpExporterOptions(); this.exporter = new OtlpTraceExporter( options, new OtlpGrpcTraceExportClient(options, mockClient.Object)); this.activity = ActivityHelper.CreateTestActivity(); this.activityBatch = new CircularBuffer <Activity>(this.NumberOfSpans); }
public void ExporterClientValidation_FlagIsNotEnabledForHttpEndpoint() { var options = new OtlpExporterOptions { Endpoint = new Uri(HttpEndpoint), }; AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", false); var exception = Record.Exception(() => ExporterClientValidation.EnsureUnencryptedSupportIsEnabled(options)); if (Environment.Version.Major == 3) { Assert.NotNull(exception); Assert.IsType <InvalidOperationException>(exception); } else { Assert.Null(exception); } }
internal static void EnsureUnencryptedSupportIsEnabled(OtlpExporterOptions options) { var version = Environment.Version; // This verification is only required for .NET Core 3.x if (version.Major != 3) { return; } if (options.Endpoint.Scheme.Equals("http", StringComparison.InvariantCultureIgnoreCase)) { if (AppContext.TryGetSwitch( "System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", out var unencryptedIsSupported) == false || unencryptedIsSupported == false) { throw new InvalidOperationException( "Calling insecure gRPC services on .NET Core 3.x requires enabling the 'System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport' switch. See: https://docs.microsoft.com/aspnet/core/grpc/troubleshoot#call-insecure-grpc-services-with-net-core-client"); } } }
private static MeterProviderBuilder AddOtlpExporter( MeterProviderBuilder builder, OtlpExporterOptions options, Action <OtlpExporterOptions> configure, IServiceProvider serviceProvider) { var initialEndpoint = options.Endpoint; configure?.Invoke(options); options.TryEnableIHttpClientFactoryIntegration(serviceProvider, "OtlpMetricExporter"); options.AppendExportPath(initialEndpoint, OtlpExporterOptions.MetricsExportPath); var metricExporter = new OtlpMetricExporter(options); var metricReader = options.MetricReaderType == MetricReaderType.Manual ? new BaseExportingMetricReader(metricExporter) : new PeriodicExportingMetricReader(metricExporter, options.PeriodicExportingMetricReaderOptions.ExportIntervalMilliseconds); metricReader.Temporality = options.AggregationTemporality; return(builder.AddReader(metricReader)); }
public void ExportResultIsSuccess() { #if NETCOREAPP3_1 // Adding the OtlpExporter creates a GrpcChannel. // This switch must be set before creating a GrpcChannel/HttpClient when calling an insecure gRPC service. // See: https://docs.microsoft.com/aspnet/core/grpc/troubleshoot#call-insecure-grpc-services-with-net-core-client AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true); #endif var exporterOptions = new OtlpExporterOptions { #if NETCOREAPP3_1 || NET5_0 Endpoint = new System.Uri($"http://{CollectorEndpoint}"), #else Endpoint = CollectorEndpoint, #endif }; var otlpExporter = new OtlpExporter(exporterOptions); var delegatingExporter = new DelegatingTestExporter <Activity>(otlpExporter); var exportActivityProcessor = new SimpleActivityExportProcessor(delegatingExporter); var activitySourceName = "otlp.collector.test"; var builder = Sdk.CreateTracerProviderBuilder() .AddSource(activitySourceName) .AddProcessor(exportActivityProcessor); using var tracerProvider = builder.Build(); var source = new ActivitySource(activitySourceName); var activity = source.StartActivity("Test Activity"); activity?.Stop(); Assert.Single(delegatingExporter.ExportResults); Assert.Equal(ExportResult.Success, delegatingExporter.ExportResults[0]); }
public void ConstructingGrpcExporterFailsWhenHttp2UnencryptedSupportIsDisabledForNetcoreapp31() { // Adding the OtlpExporter creates a GrpcChannel. // This switch must be set before creating a GrpcChannel/HttpClient when calling an insecure gRPC service. // We want to fail fast so we are disabling it // See: https://docs.microsoft.com/aspnet/core/grpc/troubleshoot#call-insecure-grpc-services-with-net-core-client AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", false); var exporterOptions = new OtlpExporterOptions { Endpoint = new Uri($"http://{CollectorHostname}:4317"), }; var exception = Record.Exception(() => new OtlpTraceExporter(exporterOptions)); if (Environment.Version.Major == 3) { Assert.NotNull(exception); } else { Assert.Null(exception); } }
public void GetTraceExportClient_GetClientForGrpcWithoutUnencryptedFlag_ThrowsException() { // Adding the OtlpExporter creates a GrpcChannel. // This switch must be set before creating a GrpcChannel when calling an insecure HTTP/2 endpoint. // See: https://docs.microsoft.com/aspnet/core/grpc/troubleshoot#call-insecure-grpc-services-with-net-core-client AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", false); var options = new OtlpExporterOptions { Protocol = OtlpExportProtocol.Grpc, }; var exception = Record.Exception(() => options.GetTraceExportClient()); if (Environment.Version.Major == 3) { Assert.NotNull(exception); Assert.IsType <InvalidOperationException>(exception); } else { Assert.Null(exception); } }
private static OpenTelemetryLoggerOptions AddOtlpExporter(OpenTelemetryLoggerOptions loggerOptions, OtlpExporterOptions exporterOptions, Action <OtlpExporterOptions> configure = null) { configure?.Invoke(exporterOptions); var otlpExporter = new OtlpLogExporter(exporterOptions); if (exporterOptions.ExportProcessorType == ExportProcessorType.Simple) { return(loggerOptions.AddProcessor(new SimpleLogRecordExportProcessor(otlpExporter))); } else { return(loggerOptions.AddProcessor(new BatchLogRecordExportProcessor( otlpExporter, exporterOptions.BatchExportProcessorOptions.MaxQueueSize, exporterOptions.BatchExportProcessorOptions.ScheduledDelayMilliseconds, exporterOptions.BatchExportProcessorOptions.ExporterTimeoutMilliseconds, exporterOptions.BatchExportProcessorOptions.MaxExportBatchSize))); } }
public OtlpHttpTraceExportClient(OtlpExporterOptions options, HttpClient httpClient = null) : base(options, httpClient) { this.exportTracesUri = this.Options.Endpoint.AppendPathIfNotPresent(OtlpExporterOptions.TracesExportPath); }
private static TracerProviderBuilder AddOtlpExporter(TracerProviderBuilder builder, OtlpExporterOptions exporterOptions, Action <OtlpExporterOptions> configure = null) { var originalEndpoint = exporterOptions.Endpoint; configure?.Invoke(exporterOptions); exporterOptions.AppendExportPath(originalEndpoint, OtlpExporterOptions.TracesExportPath); var otlpExporter = new OtlpTraceExporter(exporterOptions); if (exporterOptions.ExportProcessorType == ExportProcessorType.Simple) { return(builder.AddProcessor(new SimpleActivityExportProcessor(otlpExporter))); } else { return(builder.AddProcessor(new BatchActivityExportProcessor( otlpExporter, exporterOptions.BatchExportProcessorOptions.MaxQueueSize, exporterOptions.BatchExportProcessorOptions.ScheduledDelayMilliseconds, exporterOptions.BatchExportProcessorOptions.ExporterTimeoutMilliseconds, exporterOptions.BatchExportProcessorOptions.MaxExportBatchSize))); } }
public void MetricExportResultIsSuccess(OtlpExportProtocol protocol, string endpoint, bool useManualExport, bool forceFlush) { #if NETCOREAPP3_1 // Adding the OtlpExporter creates a GrpcChannel. // This switch must be set before creating a GrpcChannel when calling an insecure HTTP/2 endpoint. // See: https://docs.microsoft.com/aspnet/core/grpc/troubleshoot#call-insecure-grpc-services-with-net-core-client if (protocol == OtlpExportProtocol.Grpc) { AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true); } #endif using EventWaitHandle handle = new ManualResetEvent(false); var exporterOptions = new OtlpExporterOptions { Endpoint = new Uri($"http://{CollectorHostname}{endpoint}"), Protocol = protocol, }; DelegatingTestExporter <Metric> delegatingExporter = null; var meterName = "otlp.collector.test"; var builder = Sdk.CreateMeterProviderBuilder() .AddMeter(meterName); var readerOptions = new MetricReaderOptions(); readerOptions.PeriodicExportingMetricReaderOptions.ExportIntervalMilliseconds = useManualExport ? Timeout.Infinite : ExportIntervalMilliseconds; OtlpMetricExporterExtensions.AddOtlpExporter( builder, exporterOptions, readerOptions, configureExporter: null, configureExporterAndMetricReader: null, serviceProvider: null, configureExporterInstance: otlpExporter => { delegatingExporter = new DelegatingTestExporter <Metric>(otlpExporter, onExportAction: () => handle.Set()); return(delegatingExporter); }); using (var meterProvider = builder.Build()) { using var meter = new Meter(meterName); var counter = meter.CreateCounter <int>("test_counter"); counter.Add(18); Assert.NotNull(delegatingExporter); if (forceFlush) { Assert.True(meterProvider.ForceFlush()); Assert.Single(delegatingExporter.ExportResults); Assert.Equal(ExportResult.Success, delegatingExporter.ExportResults[0]); } else if (!useManualExport) { Assert.True(handle.WaitOne(ExportIntervalMilliseconds * 2)); Assert.Single(delegatingExporter.ExportResults); Assert.Equal(ExportResult.Success, delegatingExporter.ExportResults[0]); } } if (!forceFlush && useManualExport) { Assert.Single(delegatingExporter.ExportResults); Assert.Equal(ExportResult.Success, delegatingExporter.ExportResults[0]); } }
public OtlpHttpMetricsExportClient(OtlpExporterOptions options, HttpClient httpClient) : base(options, httpClient) { this.exportMetricsUri = this.Options.Endpoint; }
public TestOtlpHttpExportClient(OtlpExporterOptions options, HttpClient httpClient) : base(options, httpClient, "signal/path") { }
public OtlpHttpLogExportClient(OtlpExporterOptions options, HttpClient httpClient) : base(options, httpClient, LogsExportPath) { }
public OtlpHttpMetricsExportClient(OtlpExporterOptions options, HttpClient httpClient) : base(options, httpClient, MetricsExportPath) { }
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:")); } } }
public OtlpHttpTraceExportClient(OtlpExporterOptions options, HttpClient httpClient) : base(options, httpClient) { this.exportTracesUri = this.Options.Endpoint; }
private static MeterProviderBuilder AddOtlpExporter(MeterProviderBuilder builder, OtlpExporterOptions options, Action <OtlpExporterOptions> configure = null) { configure?.Invoke(options); var metricExporter = new OtlpMetricExporter(options); var metricReader = new PeriodicExportingMetricReader(metricExporter, options.MetricExportIntervalMilliseconds); metricReader.PreferredAggregationTemporality = options.AggregationTemporality; return(builder.AddReader(metricReader)); }
public OtlpHttpTraceExportClient(OtlpExporterOptions options, HttpClient httpClient) : base(options, httpClient, TracesExportPath) { }