Exemplo n.º 1
0
        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);
        }
Exemplo n.º 2
0
        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);
        }
Exemplo n.º 3
0
        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));
        }
Exemplo n.º 6
0
        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]);
        }
Exemplo n.º 7
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]);
            }
        }
Exemplo n.º 13
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)
 {
 }