예제 #1
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton <IWeatherDataSource, WeatherDataSource>();

            services.AddOpenTelemetryTracing(
                builder => builder
                .SetResourceBuilder(ResourceBuilder.CreateEmpty().AddService("task-processor"))
                .AddBlueprintInstrumentation()
                .AddConsoleExporter()
                .AddJaegerExporter()
                );

            services.AddHangfire(h =>
            {
                h
                .UseStorage(new SqlServerStorage("Server=(localdb)\\MSSQLLocalDB;Integrated Security=true;Initial Catalog=blueprint-examples"))
                .UseRecommendedSerializerSettings()
                .UseDashboardMetric(SqlServerStorage.ActiveConnections)
                .UseDashboardMetric(SqlServerStorage.TotalConnections)
                .UseDashboardMetric(DashboardMetrics.FailedCount)
                .UseDashboardMetric(DashboardMetrics.ProcessingCount)
                .UseDashboardMetric(DashboardMetrics.ScheduledCount)
                .UseDashboardMetric(DashboardMetrics.EnqueuedCountOrNull);
            });

            services.AddHangfireServer();

            services.AddBlueprintApi(a => a
                                     .AddBackgroundTasks(b => b.UseHangfire())
                                     .SetApplicationName("SampleTaskProcessor")
                                     .Operations(o => o
                                                 .Scan(typeof(Blueprint.Sample.WebApi.Startup).Assembly))
                                     .AddLogging());
        }
예제 #2
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();

            services.AddSingleton <IWeatherDataSource, WeatherDataSource>();

            services.AddHangfire(h =>
            {
                h
                .UseStorage(new SqlServerStorage("Server=(localdb)\\MSSQLLocalDB;Integrated Security=true;Initial Catalog=blueprint-examples"))
                .UseRecommendedSerializerSettings();
            });

            services.AddOpenTelemetryTracing(
                builder => builder
                .SetResourceBuilder(ResourceBuilder.CreateEmpty().AddService("web-api"))
                .AddAspNetCoreInstrumentation()
                .AddBlueprintInstrumentation()
                .AddJaegerExporter()
                .AddConsoleExporter()
                );

            services.AddBlueprintApi(b => b
                                     .Http()
                                     .SetApplicationName("SampleWebApi")
                                     .Operations(o => o.Scan(typeof(WebApi.Startup).Assembly))
                                     .AddTasksClient(t => t.UseHangfire())
                                     .AddOpenApi()
                                     .AddLogging()
                                     .AddHateoasLinks()
                                     .AddAuthentication(a => a.UseContextLoader <AnonymousUserAuthorisationContextFactory>())
                                     .AddAuthorisation()
                                     .AddResourceEvents <NullResourceEventRepository>());
        }
예제 #3
0
        public void ServiceResource_AutoGenerateServiceInstanceIdOff()
        {
            var resource = ResourceBuilder.CreateEmpty().AddService("my-service", autoGenerateServiceInstanceId: false).Build();

            Assert.Single(resource.Attributes);
            Assert.Contains(new KeyValuePair <string, object>(ResourceSemanticConventions.AttributeServiceName, "my-service"), resource.Attributes);
        }
예제 #4
0
        public void ServiceResource_ServiceNameAndInstance()
        {
            var resource = ResourceBuilder.CreateEmpty().AddService("my-service", serviceInstanceId: "123").Build();

            Assert.Equal(2, resource.Attributes.Count());
            Assert.Contains(new KeyValuePair <string, object>(ResourceSemanticConventions.AttributeServiceName, "my-service"), resource.Attributes);
            Assert.Contains(new KeyValuePair <string, object>(ResourceSemanticConventions.AttributeServiceInstance, "123"), resource.Attributes);
        }
예제 #5
0
        public void ServiceResource_ServiceName()
        {
            var resource = ResourceBuilder.CreateEmpty().AddService("my-service").Build();

            Assert.Equal(2, resource.Attributes.Count());
            Assert.Contains(new KeyValuePair <string, object>(ResourceSemanticConventions.AttributeServiceName, "my-service"), resource.Attributes);
            Assert.Single(resource.Attributes.Where(kvp => kvp.Key == ResourceSemanticConventions.AttributeServiceName));
            Assert.True(Guid.TryParse((string)resource.Attributes.Single(kvp => kvp.Key == ResourceSemanticConventions.AttributeServiceInstance).Value, out _));
        }
예제 #6
0
        public void ToOtlpResourceMetricsTest(bool includeServiceNameInResource)
        {
            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, "ns1"),
                });
            }

            var metrics = new List <Metric>();

            using var meter    = new Meter($"{Utils.GetCurrentMethodName()}.{includeServiceNameInResource}", "0.0.1");
            using var provider = Sdk.CreateMeterProviderBuilder()
                                 .SetResourceBuilder(resourceBuilder)
                                 .AddMeter(meter.Name)
                                 .AddInMemoryExporter(metrics)
                                 .Build();

            var counter = meter.CreateCounter <int>("counter");

            counter.Add(100);

            provider.ForceFlush();

            var batch = new Batch <Metric>(metrics.ToArray(), metrics.Count);

            var request = new OtlpCollector.ExportMetricsServiceRequest();

            request.AddMetrics(resourceBuilder.Build().ToOtlpResource(), batch);

            Assert.Single(request.ResourceMetrics);
            var resourceMetric = request.ResourceMetrics.First();
            var oltpResource   = resourceMetric.Resource;

            if (includeServiceNameInResource)
            {
                Assert.Contains(oltpResource.Attributes, (kvp) => kvp.Key == ResourceSemanticConventions.AttributeServiceName && kvp.Value.StringValue == "service-name");
                Assert.Contains(oltpResource.Attributes, (kvp) => kvp.Key == ResourceSemanticConventions.AttributeServiceNamespace && kvp.Value.StringValue == "ns1");
            }
            else
            {
                Assert.Contains(oltpResource.Attributes, (kvp) => kvp.Key == ResourceSemanticConventions.AttributeServiceName && kvp.Value.ToString().Contains("unknown_service:"));
            }

            Assert.Single(resourceMetric.InstrumentationLibraryMetrics);
            var instrumentationLibraryMetrics = resourceMetric.InstrumentationLibraryMetrics.First();

            Assert.Equal(string.Empty, instrumentationLibraryMetrics.SchemaUrl);
            Assert.Equal(meter.Name, instrumentationLibraryMetrics.InstrumentationLibrary.Name);
            Assert.Equal("0.0.1", instrumentationLibraryMetrics.InstrumentationLibrary.Version);
        }
        public void JaegerTraceExporter_SetResource_IgnoreServiceResources()
        {
            using var jaegerTraceExporter = new JaegerExporter(new JaegerExporterOptions());
            var process = jaegerTraceExporter.Process;

            jaegerTraceExporter.SetResourceAndInitializeBatch(ResourceBuilder.CreateEmpty().AddAttributes(new Dictionary <string, object>
            {
                [ResourceSemanticConventions.AttributeServiceName]      = "servicename",
                [ResourceSemanticConventions.AttributeServiceNamespace] = "servicenamespace",
            }).Build());

            Assert.Null(process.Tags);
        }
        public void JaegerTraceExporter_SetResource_CreatesTags()
        {
            using var jaegerTraceExporter = new JaegerExporter(new JaegerExporterOptions());
            var process = jaegerTraceExporter.Process;

            jaegerTraceExporter.SetResourceAndInitializeBatch(ResourceBuilder.CreateEmpty().AddAttributes(new Dictionary <string, object>
            {
                ["Tag"] = "value",
            }).Build());

            Assert.NotNull(process.Tags);
            Assert.Single(process.Tags);
            Assert.Equal("value", process.Tags["Tag"].VStr);
        }
        /// <summary>
        /// Add AWS Lambda configurations.
        /// </summary>
        /// <param name="builder"><see cref="TracerProviderBuilder"/> being configured.</param>
        /// <returns>The instance of <see cref="TracerProviderBuilder"/> to chain the calls.</returns>
        public static TracerProviderBuilder AddAWSLambdaConfigurations(this TracerProviderBuilder builder)
        {
            if (builder == null)
            {
                throw new ArgumentNullException(nameof(builder));
            }

            builder.AddSource(AWSLambdaUtils.ActivitySourceName);
            builder.SetResourceBuilder(ResourceBuilder
                                       .CreateEmpty()
                                       .AddService(AWSLambdaUtils.GetFunctionName(), null, null, false)
                                       .AddTelemetrySdk()
                                       .AddAttributes(AWSLambdaResourceDetector.Detect()));

            return(builder);
        }
예제 #10
0
        public void JaegerTraceExporter_SetResource_CombinesTags()
        {
            using var jaegerTraceExporter = new JaegerExporter(new JaegerExporterOptions());
            var process = jaegerTraceExporter.Process;

            process.Tags = new Dictionary<string, JaegerTag> { ["Tag1"] = new KeyValuePair<string, object>("Tag1", "value1").ToJaegerTag() };

            jaegerTraceExporter.SetResourceAndInitializeBatch(ResourceBuilder.CreateEmpty().AddAttributes(new Dictionary<string, object>
            {
                ["Tag2"] = "value2",
            }).Build());

            Assert.NotNull(process.Tags);
            Assert.Equal(2, process.Tags.Count);
            Assert.Equal("value1", process.Tags["Tag1"].VStr);
            Assert.Equal("value2", process.Tags["Tag2"].VStr);
        }
        public void JaegerTraceExporter_SetResource_UpdatesServiceName()
        {
            using var jaegerTraceExporter = new JaegerExporter(new JaegerExporterOptions());
            var process = jaegerTraceExporter.Process;

            process.ServiceName = "TestService";

            jaegerTraceExporter.SetResourceAndInitializeBatch(Resource.Empty);

            Assert.Equal("TestService", process.ServiceName);

            jaegerTraceExporter.SetResourceAndInitializeBatch(ResourceBuilder.CreateEmpty().AddService("MyService").Build());

            Assert.Equal("MyService", process.ServiceName);

            jaegerTraceExporter.SetResourceAndInitializeBatch(ResourceBuilder.CreateEmpty().AddService("MyService", "MyNamespace").Build());

            Assert.Equal("MyNamespace.MyService", process.ServiceName);
        }
예제 #12
0
        private static ResourceBuilder SetupResourceBuilder(InstrumentationConfig conf)
        {
            var resourceBuilder = ResourceBuilder.CreateEmpty()
                                  .AddService(conf.ServiceName, serviceVersion: conf.ServiceVersion)
                                  .AddAttributes(new Dictionary <string, object>
            {
                { OpenTelemetryResourceAttributes.AttributeDeploymentEnvironment, conf.DeploymentEnvironment },
                { OpenTelemetryResourceAttributes.AttributeTelemetrySdkLanguage, "dotnet" },
                { "lightstep.access_token", conf.LightStepProjectToken }
            });

            if (conf.ResourceEnhancers == null)
            {
                return(resourceBuilder);
            }

            foreach (var resourceEnhancer in conf.ResourceEnhancers)
            {
                resourceEnhancer?.RegisterResourceAttributes(resourceBuilder);
            }

            return(resourceBuilder);
        }
예제 #13
0
        public void ToOtlpResourceTest(bool includeServiceNameInResource)
        {
            // Targeted test to cover OTel Resource to OTLP Resource
            // conversion, independent of signals.
            var resourceBuilder = ResourceBuilder.CreateEmpty();

            if (includeServiceNameInResource)
            {
                resourceBuilder.AddService("service-name", "ns1");
            }

            var resource     = resourceBuilder.Build();
            var otlpResource = resource.ToOtlpResource();

            if (includeServiceNameInResource)
            {
                Assert.Contains(otlpResource.Attributes, (kvp) => kvp.Key == ResourceSemanticConventions.AttributeServiceName && kvp.Value.StringValue == "service-name");
                Assert.Contains(otlpResource.Attributes, (kvp) => kvp.Key == ResourceSemanticConventions.AttributeServiceNamespace && kvp.Value.StringValue == "ns1");
            }
            else
            {
                Assert.Contains(otlpResource.Attributes, (kvp) => kvp.Key == ResourceSemanticConventions.AttributeServiceName && kvp.Value.ToString().Contains("unknown_service:"));
            }
        }
예제 #14
0
        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 void ToOtlpResourceMetricsTest(bool includeServiceNameInResource)
        {
            using var exporter = new OtlpMetricsExporter(
                      new OtlpExporterOptions(),
                      new NoopMetricsServiceClient());

            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, "ns1"),
                });
            }

            var tags = new KeyValuePair <string, object>[]
            {
                new KeyValuePair <string, object>("key1", "value1"),
                new KeyValuePair <string, object>("key2", "value2"),
            };

            var processor = new PullMetricProcessor(new TestExporter <MetricItem>(RunTest), true);

            using var provider = Sdk.CreateMeterProviderBuilder()
                                 .SetResourceBuilder(resourceBuilder)
                                 .AddSource("TestMeter")
                                 .AddMetricProcessor(processor)
                                 .Build();

            exporter.ParentProvider = provider;

            using var meter = new Meter("TestMeter", "0.0.1");

            var counter = meter.CreateCounter <int>("counter");

            counter.Add(100, tags);

            var testCompleted = false;

            // Invokes the TestExporter which will invoke RunTest
            processor.PullRequest();

            Assert.True(testCompleted);

            void RunTest(Batch <MetricItem> metricItem)
            {
                var request = new OtlpCollector.ExportMetricsServiceRequest();

                request.AddBatch(exporter.ProcessResource, metricItem);

                Assert.Single(request.ResourceMetrics);
                var resourceMetric = request.ResourceMetrics.First();
                var oltpResource   = resourceMetric.Resource;

                if (includeServiceNameInResource)
                {
                    Assert.Contains(oltpResource.Attributes, (kvp) => kvp.Key == ResourceSemanticConventions.AttributeServiceName && kvp.Value.StringValue == "service-name");
                    Assert.Contains(oltpResource.Attributes, (kvp) => kvp.Key == ResourceSemanticConventions.AttributeServiceNamespace && kvp.Value.StringValue == "ns1");
                }
                else
                {
                    Assert.Contains(oltpResource.Attributes, (kvp) => kvp.Key == ResourceSemanticConventions.AttributeServiceName && kvp.Value.ToString().Contains("unknown_service:"));
                }

                Assert.Single(resourceMetric.InstrumentationLibraryMetrics);
                var instrumentationLibraryMetrics = resourceMetric.InstrumentationLibraryMetrics.First();

                Assert.Equal(string.Empty, instrumentationLibraryMetrics.SchemaUrl);
                Assert.Equal("TestMeter", instrumentationLibraryMetrics.InstrumentationLibrary.Name);
                Assert.Equal("0.0.1", instrumentationLibraryMetrics.InstrumentationLibrary.Version);

                Assert.Single(instrumentationLibraryMetrics.Metrics);

                foreach (var metric in instrumentationLibraryMetrics.Metrics)
                {
                    Assert.Equal(string.Empty, metric.Description);
                    Assert.Equal(string.Empty, metric.Unit);
                    Assert.Equal("counter", metric.Name);

                    Assert.Equal(OtlpMetrics.Metric.DataOneofCase.Sum, metric.DataCase);
                    Assert.True(metric.Sum.IsMonotonic);
                    Assert.Equal(OtlpMetrics.AggregationTemporality.Delta, metric.Sum.AggregationTemporality);

                    Assert.Single(metric.Sum.DataPoints);
                    var dataPoint = metric.Sum.DataPoints.First();
                    Assert.True(dataPoint.StartTimeUnixNano > 0);
                    Assert.True(dataPoint.TimeUnixNano > 0);
                    Assert.Equal(OtlpMetrics.NumberDataPoint.ValueOneofCase.AsInt, dataPoint.ValueCase);
                    Assert.Equal(100, dataPoint.AsInt);

#pragma warning disable CS0612 // Type or member is obsolete
                    Assert.Empty(dataPoint.Labels);
#pragma warning restore CS0612 // Type or member is obsolete
                    OtlpTestHelpers.AssertOtlpAttributes(tags.ToList(), dataPoint.Attributes);

                    Assert.Empty(dataPoint.Exemplars);
                }

                testCompleted = true;
            }
        }
        public void TestCounterToOtlpMetric(string name, string description, string unit, long?longValue, double?doubleValue, MetricReaderTemporalityPreference aggregationTemporality, bool isMonotonic, params object[] keysValues)
        {
            var metrics = new List <Metric>();

            using var meter    = new Meter(Utils.GetCurrentMethodName());
            using var provider = Sdk.CreateMeterProviderBuilder()
                                 .AddMeter(meter.Name)
                                 .AddInMemoryExporter(metrics, metricReaderOptions =>
            {
                metricReaderOptions.TemporalityPreference = aggregationTemporality;
            })
                                 .Build();

            var attributes = ToAttributes(keysValues).ToArray();

            if (longValue.HasValue)
            {
                var counter = meter.CreateCounter <long>(name, unit, description);
                counter.Add(longValue.Value, attributes);
            }
            else
            {
                var counter = meter.CreateCounter <double>(name, unit, description);
                counter.Add(doubleValue.Value, attributes);
            }

            provider.ForceFlush();

            var batch = new Batch <Metric>(metrics.ToArray(), metrics.Count);

            var request = new OtlpCollector.ExportMetricsServiceRequest();

            request.AddMetrics(ResourceBuilder.CreateEmpty().Build().ToOtlpResource(), batch);

            var resourceMetric = request.ResourceMetrics.Single();
            var scopeMetrics   = resourceMetric.ScopeMetrics.Single();
            var actual         = scopeMetrics.Metrics.Single();

            Assert.Equal(name, actual.Name);
            Assert.Equal(description ?? string.Empty, actual.Description);
            Assert.Equal(unit ?? string.Empty, actual.Unit);

            Assert.Equal(OtlpMetrics.Metric.DataOneofCase.Sum, actual.DataCase);

            Assert.Null(actual.Gauge);
            Assert.NotNull(actual.Sum);
            Assert.Null(actual.Histogram);
            Assert.Null(actual.ExponentialHistogram);
            Assert.Null(actual.Summary);

            Assert.Equal(isMonotonic, actual.Sum.IsMonotonic);

            var otlpAggregationTemporality = aggregationTemporality == MetricReaderTemporalityPreference.Cumulative
                ? OtlpMetrics.AggregationTemporality.Cumulative
                : OtlpMetrics.AggregationTemporality.Delta;

            Assert.Equal(otlpAggregationTemporality, actual.Sum.AggregationTemporality);

            Assert.Single(actual.Sum.DataPoints);
            var dataPoint = actual.Sum.DataPoints.First();

            Assert.True(dataPoint.StartTimeUnixNano > 0);
            Assert.True(dataPoint.TimeUnixNano > 0);

            if (longValue.HasValue)
            {
                Assert.Equal(OtlpMetrics.NumberDataPoint.ValueOneofCase.AsInt, dataPoint.ValueCase);
                Assert.Equal(longValue, dataPoint.AsInt);
            }
            else
            {
                Assert.Equal(OtlpMetrics.NumberDataPoint.ValueOneofCase.AsDouble, dataPoint.ValueCase);
                Assert.Equal(doubleValue, dataPoint.AsDouble);
            }

            if (attributes.Length > 0)
            {
                OtlpTestHelpers.AssertOtlpAttributes(attributes, dataPoint.Attributes);
            }
            else
            {
                Assert.Empty(dataPoint.Attributes);
            }

            Assert.Empty(dataPoint.Exemplars);
        }
        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:"));
                }
            }
        }
예제 #18
0
        public void TestGaugeToOtlpMetric(string name, string description, string unit, long?longValue, double?doubleValue)
        {
            var metrics = new List <Metric>();

            using var meter    = new Meter(Utils.GetCurrentMethodName());
            using var provider = Sdk.CreateMeterProviderBuilder()
                                 .AddMeter(meter.Name)
                                 .AddInMemoryExporter(metrics)
                                 .Build();

            if (longValue.HasValue)
            {
                meter.CreateObservableGauge(name, () => longValue.Value, unit, description);
            }
            else
            {
                meter.CreateObservableGauge(name, () => doubleValue.Value, unit, description);
            }

            provider.ForceFlush();

            var batch = new Batch <Metric>(metrics.ToArray(), metrics.Count);

            var request = new OtlpCollector.ExportMetricsServiceRequest();

            request.AddMetrics(ResourceBuilder.CreateEmpty().Build().ToOtlpResource(), batch);

            var resourceMetric = request.ResourceMetrics.Single();
            var instrumentationLibraryMetrics = resourceMetric.InstrumentationLibraryMetrics.Single();
            var actual = instrumentationLibraryMetrics.Metrics.Single();

            Assert.Equal(name, actual.Name);
            Assert.Equal(description ?? string.Empty, actual.Description);
            Assert.Equal(unit ?? string.Empty, actual.Unit);

            Assert.Equal(OtlpMetrics.Metric.DataOneofCase.Gauge, actual.DataCase);

            Assert.NotNull(actual.Gauge);
            Assert.Null(actual.Sum);
            Assert.Null(actual.Histogram);
            Assert.Null(actual.ExponentialHistogram);
            Assert.Null(actual.Summary);

            Assert.Single(actual.Gauge.DataPoints);
            var dataPoint = actual.Gauge.DataPoints.First();

            Assert.True(dataPoint.StartTimeUnixNano > 0);
            Assert.True(dataPoint.TimeUnixNano > 0);

            if (longValue.HasValue)
            {
                Assert.Equal(OtlpMetrics.NumberDataPoint.ValueOneofCase.AsInt, dataPoint.ValueCase);
                Assert.Equal(longValue, dataPoint.AsInt);
            }
            else
            {
                Assert.Equal(OtlpMetrics.NumberDataPoint.ValueOneofCase.AsDouble, dataPoint.ValueCase);
                Assert.Equal(doubleValue, dataPoint.AsDouble);
            }

            Assert.Empty(dataPoint.Attributes);

            Assert.Empty(dataPoint.Exemplars);

#pragma warning disable CS0612 // Type or member is obsolete
            Assert.Null(actual.IntGauge);
            Assert.Null(actual.IntSum);
            Assert.Null(actual.IntHistogram);
            Assert.Empty(dataPoint.Labels);
#pragma warning restore CS0612 // Type or member is obsolete
        }
예제 #19
0
        public void TestHistogramToOltpMetric(string name, string description, string unit, long?longValue, double?doubleValue, AggregationTemporality aggregationTemporality, params object[] keysValues)
        {
            var metrics = new List <Metric>();

            var metricReader = new BaseExportingMetricReader(new InMemoryExporter <Metric>(metrics));

            metricReader.Temporality = aggregationTemporality;

            using var meter    = new Meter(Utils.GetCurrentMethodName());
            using var provider = Sdk.CreateMeterProviderBuilder()
                                 .AddMeter(meter.Name)
                                 .AddReader(metricReader)
                                 .Build();

            var attributes = ToAttributes(keysValues).ToArray();

            if (longValue.HasValue)
            {
                var histogram = meter.CreateHistogram <long>(name, unit, description);
                histogram.Record(longValue.Value, attributes);
            }
            else
            {
                var histogram = meter.CreateHistogram <double>(name, unit, description);
                histogram.Record(doubleValue.Value, attributes);
            }

            provider.ForceFlush();

            var batch = new Batch <Metric>(metrics.ToArray(), metrics.Count);

            var request = new OtlpCollector.ExportMetricsServiceRequest();

            request.AddMetrics(ResourceBuilder.CreateEmpty().Build().ToOtlpResource(), batch);

            var resourceMetric = request.ResourceMetrics.Single();
            var instrumentationLibraryMetrics = resourceMetric.InstrumentationLibraryMetrics.Single();
            var actual = instrumentationLibraryMetrics.Metrics.Single();

            Assert.Equal(name, actual.Name);
            Assert.Equal(description ?? string.Empty, actual.Description);
            Assert.Equal(unit ?? string.Empty, actual.Unit);

            Assert.Equal(OtlpMetrics.Metric.DataOneofCase.Histogram, actual.DataCase);

            Assert.Null(actual.Gauge);
            Assert.Null(actual.Sum);
            Assert.NotNull(actual.Histogram);
            Assert.Null(actual.ExponentialHistogram);
            Assert.Null(actual.Summary);

            var otlpAggregationTemporality = aggregationTemporality == AggregationTemporality.Cumulative
                ? OtlpMetrics.AggregationTemporality.Cumulative
                : OtlpMetrics.AggregationTemporality.Delta;

            Assert.Equal(otlpAggregationTemporality, actual.Histogram.AggregationTemporality);

            Assert.Single(actual.Histogram.DataPoints);
            var dataPoint = actual.Histogram.DataPoints.First();

            Assert.True(dataPoint.StartTimeUnixNano > 0);
            Assert.True(dataPoint.TimeUnixNano > 0);

            Assert.Equal(1UL, dataPoint.Count);

            if (longValue.HasValue)
            {
                Assert.Equal((double)longValue, dataPoint.Sum);
            }
            else
            {
                Assert.Equal(doubleValue, dataPoint.Sum);
            }

            int bucketIndex;

            for (bucketIndex = 0; bucketIndex < dataPoint.ExplicitBounds.Count; ++bucketIndex)
            {
                if (dataPoint.Sum <= dataPoint.ExplicitBounds[bucketIndex])
                {
                    break;
                }

                Assert.Equal(0UL, dataPoint.BucketCounts[bucketIndex]);
            }

            Assert.Equal(1UL, dataPoint.BucketCounts[bucketIndex]);

            if (attributes.Length > 0)
            {
                OtlpTestHelpers.AssertOtlpAttributes(attributes, dataPoint.Attributes);
            }
            else
            {
                Assert.Empty(dataPoint.Attributes);
            }

            Assert.Empty(dataPoint.Exemplars);

#pragma warning disable CS0612 // Type or member is obsolete
            Assert.Null(actual.IntGauge);
            Assert.Null(actual.IntSum);
            Assert.Null(actual.IntHistogram);
            Assert.Empty(dataPoint.Labels);
#pragma warning restore CS0612 // Type or member is obsolete
        }
        public void ToOtlpResourceMetricsTest(bool includeServiceNameInResource)
        {
            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, "ns1"),
                });
            }

            var tags = new KeyValuePair <string, object>[]
            {
                new KeyValuePair <string, object>("key1", "value1"),
                new KeyValuePair <string, object>("key2", "value2"),
            };

            using var meter = new Meter($"{Utils.GetCurrentMethodName()}.{includeServiceNameInResource}", "0.0.1");

            var exportedItems = new List <Metric>();

            using var provider = Sdk.CreateMeterProviderBuilder()
                                 .SetResourceBuilder(resourceBuilder)
                                 .AddMeter(meter.Name)
                                 .AddReader(new BaseExportingMetricReader(new InMemoryExporter <Metric>(exportedItems))
            {
                PreferredAggregationTemporality = AggregationTemporality.Delta
            })
                                 .Build();

            var counter = meter.CreateCounter <int>("counter");

            counter.Add(100, tags);

            var testCompleted = false;

            provider.ForceFlush();

            var batch = new Batch <Metric>(exportedItems.ToArray(), exportedItems.Count);

            RunTest(batch);

            Assert.True(testCompleted);

            void RunTest(Batch <Metric> metrics)
            {
                var request = new OtlpCollector.ExportMetricsServiceRequest();

                request.AddMetrics(resourceBuilder.Build().ToOtlpResource(), metrics);

                Assert.Single(request.ResourceMetrics);
                var resourceMetric = request.ResourceMetrics.First();
                var oltpResource   = resourceMetric.Resource;

                if (includeServiceNameInResource)
                {
                    Assert.Contains(oltpResource.Attributes, (kvp) => kvp.Key == ResourceSemanticConventions.AttributeServiceName && kvp.Value.StringValue == "service-name");
                    Assert.Contains(oltpResource.Attributes, (kvp) => kvp.Key == ResourceSemanticConventions.AttributeServiceNamespace && kvp.Value.StringValue == "ns1");
                }
                else
                {
                    Assert.Contains(oltpResource.Attributes, (kvp) => kvp.Key == ResourceSemanticConventions.AttributeServiceName && kvp.Value.ToString().Contains("unknown_service:"));
                }

                Assert.Single(resourceMetric.InstrumentationLibraryMetrics);
                var instrumentationLibraryMetrics = resourceMetric.InstrumentationLibraryMetrics.First();

                Assert.Equal(string.Empty, instrumentationLibraryMetrics.SchemaUrl);
                Assert.Equal(meter.Name, instrumentationLibraryMetrics.InstrumentationLibrary.Name);
                Assert.Equal("0.0.1", instrumentationLibraryMetrics.InstrumentationLibrary.Version);

                Assert.Single(instrumentationLibraryMetrics.Metrics);

                foreach (var metric in instrumentationLibraryMetrics.Metrics)
                {
                    Assert.Equal(string.Empty, metric.Description);
                    Assert.Equal(string.Empty, metric.Unit);
                    Assert.Equal("counter", metric.Name);

                    Assert.Equal(OtlpMetrics.Metric.DataOneofCase.Sum, metric.DataCase);
                    Assert.True(metric.Sum.IsMonotonic);
                    Assert.Equal(OtlpMetrics.AggregationTemporality.Delta, metric.Sum.AggregationTemporality);

                    Assert.Single(metric.Sum.DataPoints);
                    var dataPoint = metric.Sum.DataPoints.First();
                    Assert.True(dataPoint.StartTimeUnixNano > 0);
                    Assert.True(dataPoint.TimeUnixNano > 0);
                    Assert.Equal(OtlpMetrics.NumberDataPoint.ValueOneofCase.AsInt, dataPoint.ValueCase);
                    Assert.Equal(100, dataPoint.AsInt);

#pragma warning disable CS0612 // Type or member is obsolete
                    Assert.Empty(dataPoint.Labels);
#pragma warning restore CS0612 // Type or member is obsolete
                    OtlpTestHelpers.AssertOtlpAttributes(tags.ToList(), dataPoint.Attributes);

                    Assert.Empty(dataPoint.Exemplars);
                }

                testCompleted = true;
            }
        }