コード例 #1
0
        public async Task Trace_Header()
        {
            string traceId = TraceIdFactory.Create().NextId();
            ulong  spanId  = SpanIdFactory.Create().NextId();

            string testId    = Utils.GetTestId();
            var    startTime = Timestamp.FromDateTime(DateTime.UtcNow);
            var    builder   = new WebHostBuilder().UseStartup <TraceTestNoBufferLowQpsApplication>();

            using (var server = new TestServer(builder))
            {
                var client = server.CreateClient();

                var header = TraceHeaderContext.Create(traceId, spanId, shouldTrace: true);
                client.DefaultRequestHeaders.Add(TraceHeaderContext.TraceHeader, header.ToString());
                await client.GetAsync($"/Trace/Trace/{testId}");
            }

            var spanName = TraceController.GetMessage(nameof(TraceController.Trace), testId);
            var trace    = _polling.GetTrace(spanName, startTime);

            Assert.NotNull(trace);
            Assert.Equal(traceId, trace.TraceId);
            Assert.Equal(2, trace.Spans.Count);
            var span = trace.Spans.First(s => s.Name.StartsWith("/Trace"));

            Assert.Equal(spanId, span.ParentSpanId);
        }
コード例 #2
0
        public async Task Trace_Header()
        {
            string traceId = _traceIdFactory.NextId();
            ulong  spanId  = _spanIdFactory.NextId();

            var uri           = $"/Trace/{nameof(TraceController.Trace)}/{_testId}";
            var childSpanName = EntryData.GetMessage(nameof(TraceController.Trace), _testId);

            using (var server = new TestServer(new WebHostBuilder().UseStartup <TraceTestNoBufferLowQpsApplication>()))
                using (var client = server.CreateClient())
                {
                    var header = TraceHeaderContext.Create(traceId, spanId, shouldTrace: true);
                    client.DefaultRequestHeaders.Add(TraceHeaderContext.TraceHeader, header.ToString());

                    var response = await client.GetAsync(uri);

                    var trace = _polling.GetTrace(uri, _startTime);

                    TraceEntryVerifiers.AssertParentChildSpan(trace, uri, childSpanName);

                    Assert.Equal(traceId, trace.TraceId);
                    var parentSpan = trace.Spans.First(s => s.Name == uri);
                    Assert.Equal(spanId, parentSpan.ParentSpanId);

                    Assert.True(response.Headers.Contains(TraceHeaderContext.TraceHeader));
                    var returnedHeader = response.Headers.GetValues(TraceHeaderContext.TraceHeader).Single();
                    var headerContext  = TraceHeaderContext.FromHeader(returnedHeader);
                    Assert.Equal(traceId, headerContext.TraceId);
                    Assert.Equal(spanId, headerContext.SpanId);
                    Assert.True(headerContext.ShouldTrace);
                }
        }
コード例 #3
0
        public void Log_Trace()
        {
            string traceId       = "105445aa7843bc8bf206b12000100f00";
            string fullTraceName = TraceTarget.ForProject(ProjectId).GetFullTraceName(traceId);

            Predicate <IEnumerable <LogEntry> > matcher = logEntries =>
            {
                LogEntry entry = logEntries.Single();
                return(entry.LogName == new LogName(ProjectId, BaseLogName).ToString() &&
                       entry.Trace == fullTraceName);
            };

            var tracerContext     = TraceHeaderContext.Create(traceId, 81237123, null);
            HeaderDictionary dict = new HeaderDictionary();

            dict[TraceHeaderContext.TraceHeader] = tracerContext.ToString();

            var mockServiceProvider = new Mock <IServiceProvider>();
            var mockAccessor        = new Mock <IHttpContextAccessor>();
            var mockContext         = new Mock <HttpContext>();
            var mockRequest         = new Mock <HttpRequest>();

            mockServiceProvider.Setup(sp => sp.GetService(typeof(IHttpContextAccessor))).Returns(mockAccessor.Object);
            mockAccessor.Setup(a => a.HttpContext).Returns(mockContext.Object);
            mockContext.Setup(c => c.Request).Returns(mockRequest.Object);
            mockRequest.Setup(r => r.Headers).Returns(dict);

            var mockConsumer = new Mock <IConsumer <LogEntry> >();

            mockConsumer.Setup(c => c.Receive(Match.Create(matcher)));
            var logger = GetLogger(mockConsumer.Object, LogLevel.Information, serviceProvider: mockServiceProvider.Object, logName: BaseLogName);

            logger.Log(LogLevel.Error, 0, LogMessage, s_exception, Formatter);
            mockConsumer.VerifyAll();
        }
コード例 #4
0
        public async Task Trace_Header()
        {
            string traceId = TraceIdFactory.Create().NextId();
            ulong  spanId  = SpanIdFactory.Create().NextId();

            string testId    = Utils.GetTestId();
            var    startTime = Timestamp.FromDateTime(DateTime.UtcNow);

            var client = _noBufferLowQps.CreateClient();

            var header = TraceHeaderContext.Create(traceId, spanId, shouldTrace: true);

            client.DefaultRequestHeaders.Add(TraceHeaderContext.TraceHeader, header.ToString());
            var response = await client.GetAsync($"/Trace/Trace/{testId}");

            var spanName = TraceController.GetMessage(nameof(TraceController.Trace), testId);
            var trace    = _polling.GetTrace(spanName, startTime);

            Assert.NotNull(trace);
            Assert.Equal(traceId, trace.TraceId);
            Assert.Equal(2, trace.Spans.Count);
            var span = trace.Spans.First(s => s.Name.StartsWith("/Trace"));

            Assert.Equal(spanId, span.ParentSpanId);

            Assert.True(response.Headers.Contains(TraceHeaderContext.TraceHeader));
            var returnedHeader = response.Headers.GetValues(TraceHeaderContext.TraceHeader).Single();
            var headerContext  = TraceHeaderContext.FromHeader(returnedHeader);

            Assert.Equal(traceId, headerContext.TraceId);
            Assert.Equal(spanId, headerContext.SpanId);
            Assert.True(headerContext.ShouldTrace);
        }
コード例 #5
0
        public async Task Logging_Trace_FromHeader_Implicit()
        {
            string traceId = s_traceIdFactory.NextId();
            ulong  spanId  = s_spanIdFactory.NextId();
            string testId  = IdGenerator.FromGuid();

            using (var server = GetTestServer <NoBufferWarningLoggerTestApplication>())
                using (var client = server.CreateClient())
                {
                    client.DefaultRequestHeaders.Add(TraceHeaderContext.TraceHeader,
                                                     TraceHeaderContext.Create(traceId, spanId, true).ToString());
                    await client.GetAsync($"/Main/Critical/{testId}");
                }

            _fixture.AddValidator(testId, results =>
            {
                // We only have one log entry.
                LogEntry entry = Assert.Single(results);

                // And the resource name of the trace associated to it points to the trace
                // we specified on the header.
                Assert.Contains(TestEnvironment.GetTestProjectId(), entry.Trace);
                Assert.Contains(traceId, entry.Trace);

                // Let's get our trace.
                var trace = s_tracePolling.GetTrace(traceId);
                Assert.NotNull(trace);

                // The span associated to our entry needs to be part of that trace.
                // (We created this span on the middleware to encompass the whole request)
                var entrySpan = Assert.Single(trace.Spans, s => EntryData.SpanIdToHex(s.SpanId) == entry.SpanId);
                // And its parent needs to be the span specified in the header
                Assert.Equal(spanId, entrySpan.ParentSpanId);
            });
        }
コード例 #6
0
        public async Task Logging_Trace_FromHeader_MultipleSpans()
        {
            string traceId = s_traceIdFactory.NextId();
            ulong  spanId  = s_spanIdFactory.NextId();
            string testId  = IdGenerator.FromGuid();

            var builder = new WebHostBuilder().UseStartup <NoBufferWarningLoggerTestApplication>();

            using (var server = new TestServer(builder))
                using (var client = server.CreateClient())
                {
                    client.DefaultRequestHeaders.Add(TraceHeaderContext.TraceHeader,
                                                     TraceHeaderContext.Create(traceId, spanId, true).ToString());
                    await client.GetAsync($"/Main/{nameof(MainController.LogsInDifferentSpans)}/{testId}");
                }

            _fixture.AddValidator(testId, results =>
            {
                // Span: span-1
                //       Log: span-1
                //       Span: span-1-2
                //             Log: span-1-2
                // Span: span-2
                //       Log: span-2

                string projectId = TestEnvironment.GetTestProjectId();

                // We have 3 logs.
                Assert.Equal(3, results.Count);
                // And the resource name of the trace associated to all of them points to the trace
                // we specified on the header.
                Assert.DoesNotContain(results, entry => !entry.Trace.Contains(projectId));
                Assert.DoesNotContain(results, entry => !entry.Trace.Contains(traceId));

                // Let's get our trace.
                var trace = s_tracePolling.GetTrace(traceId);
                Assert.NotNull(trace);

                // Let's check that all the entries are associated to the correct spans.
                var logEntry1  = Assert.Single(results, e => e.JsonPayload.Fields["message"].StringValue.EndsWith("log-1"));
                var logEntry12 = Assert.Single(results, e => e.JsonPayload.Fields["message"].StringValue.EndsWith("log-1-2"));
                var logEntry2  = Assert.Single(results, e => e.JsonPayload.Fields["message"].StringValue.EndsWith("log-2"));

                var span1 = Assert.Single(trace.Spans, s => EntryData.SpanIdToHex(s.SpanId) == logEntry1.SpanId);
                Assert.EndsWith("span-1", span1.Name);
                var span12 = Assert.Single(trace.Spans, s => EntryData.SpanIdToHex(s.SpanId) == logEntry12.SpanId);
                Assert.EndsWith("span-1-2", span12.Name);
                var span2 = Assert.Single(trace.Spans, s => EntryData.SpanIdToHex(s.SpanId) == logEntry2.SpanId);
                Assert.EndsWith("span-2", span2.Name);

                // Let's check that the spans are correctly created and descend from the span we specified in the header.
                // span-1-2 is a child of span-1
                Assert.Equal(span12.ParentSpanId, span1.SpanId);
                // span-1 and span-2 have the same parent
                Assert.Equal(span1.ParentSpanId, span2.ParentSpanId);
                // The grandparent of span-1 and span-2 is the span we specified on the header.
                var parentSpan = Assert.Single(trace.Spans, s => s.SpanId == span1.ParentSpanId);
                Assert.Equal(spanId, parentSpan.ParentSpanId);
            });
        }
コード例 #7
0
        public void Create()
        {
            var context = TraceHeaderContext.Create(TraceId, SpanId, true);

            Assert.Equal(SpanId, context.SpanId);
            Assert.Equal(TraceId, context.TraceId);
            Assert.True(context.ShouldTrace);
        }
コード例 #8
0
        /// <summary>
        /// Invokes the next <see cref="RequestDelegate"/> and traces the time
        /// taken for the next delegate to run, reporting the results to the
        /// Stackdriver Trace API.
        /// </summary>
        /// <param name="httpContext">The current HTTP context.</param>
        /// <param name="traceHeaderContext">Information from the current request header. Must not be null.</param>
        public async Task Invoke(HttpContext httpContext, TraceHeaderContext traceHeaderContext)
        {
            GaxPreconditions.CheckNotNull(traceHeaderContext, nameof(traceHeaderContext));

            // Create a tracer for the given request and set it on the context manager so
            // the tracer can be used in other places.
            var tracer = _tracerFactory(traceHeaderContext);

            ContextTracerManager.SetCurrentTracer(tracer);

            if (tracer.GetCurrentTraceId() == null)
            {
                await _next(httpContext).ConfigureAwait(false);
            }
            else
            {
                if (traceHeaderContext.TraceId != null)
                {
                    // Set the trace updated trace header on the response.
                    var updatedHeaderContext = TraceHeaderContext.Create(
                        tracer.GetCurrentTraceId(), tracer.GetCurrentSpanId() ?? 0, true);
                    httpContext.Response.Headers.Add(
                        TraceHeaderContext.TraceHeader, updatedHeaderContext.ToString());
                }

                // Trace the delegate and annotate it with information from the current
                // HTTP context.
                var traceName = await _nameProvider.GetTraceNameAsync(httpContext).ConfigureAwait(false);

                var span = tracer.StartSpan(traceName);
                try
                {
                    await _next(httpContext).ConfigureAwait(false);
                }
                catch (Exception exception)
                {
                    try
                    {
                        StackTrace stackTrace = new StackTrace(exception, true);
                        tracer.SetStackTrace(stackTrace);
                    }
                    catch (Exception innerException)
                    {
                        throw new AggregateException(innerException, exception);
                    }
                    throw;
                }
                finally
                {
                    tracer.AnnotateSpan(Labels.AgentLabel);
                    tracer.AnnotateSpan(Labels.FromHttpContext(httpContext));
                    span.Dispose();
                }
            }
        }
コード例 #9
0
        public void ToStringTest()
        {
            var context = TraceHeaderContext.Create(TraceId, SpanId, true);

            Assert.Equal($"{TraceId}/{SpanId};o=1", context.ToString());

            context = TraceHeaderContext.Create(TraceId, SpanId, null);
            Assert.Equal($"{TraceId}/{SpanId};", context.ToString());

            context = TraceHeaderContext.Create(TraceId, SpanId, false);
            Assert.Equal($"{TraceId}/{SpanId};o=0", context.ToString());

            context = TraceHeaderContext.Create(null, null, false);
            Assert.Equal("/;o=0", context.ToString());
        }
コード例 #10
0
        /// <summary>
        /// Invokes the next <see cref="RequestDelegate"/> and traces the time
        /// taken for the next delegate to run, reporting the results to the
        /// Stackdriver Trace API.
        /// </summary>
        /// <param name="httpContext">The current http context.</param>
        /// <param name="traceHeaderContext">Information from the current requrest header. Cannot be null.</param>
        public async Task Invoke(HttpContext httpContext, TraceHeaderContext traceHeaderContext)
        {
            GaxPreconditions.CheckNotNull(traceHeaderContext, nameof(traceHeaderContext));

            // Create a tracer for the given request and set it on the HttpContext so
            // the tracer can be used in other places.
            var tracer = _tracerFactory.CreateTracer(traceHeaderContext);

            ContextTracerManager.SetCurrentTracer(_accessor, tracer);

            if (tracer.GetCurrentTraceId() == null)
            {
                await _next(httpContext).ConfigureAwait(false);
            }
            else
            {
                if (traceHeaderContext.TraceId != null)
                {
                    // Set the trace updated trace header on the response.
                    var updatedHeaderContext = TraceHeaderContext.Create(
                        tracer.GetCurrentTraceId(), tracer.GetCurrentSpanId() ?? 0, true);
                    httpContext.Response.Headers.Add(
                        TraceHeaderContext.TraceHeader, updatedHeaderContext.ToString());
                }

                // Trace the delegate and annotate it with information from the current
                // http context.
                tracer.StartSpan(httpContext.Request.Path);
                try
                {
                    await _next(httpContext).ConfigureAwait(false);
                }
                catch (Exception e)
                {
                    StackTrace stackTrace = new StackTrace(e, true);
                    tracer.SetStackTrace(stackTrace);
                    throw;
                }
                finally
                {
                    tracer.AnnotateSpan(Labels.AgentLabel);
                    tracer.AnnotateSpan(Labels.FromHttpContext(httpContext));
                    tracer.EndSpan();
                }
            }
        }
コード例 #11
0
        public void CreateManagedTracer()
        {
            var context           = TraceHeaderContext.Create(null, null, false);
            var tracerFactoryMock = new Mock <IManagedTracerFactory>();

            tracerFactoryMock.Setup(f => f.CreateTracer(context)).Returns(NullManagedTracer.Instance);
            var mockProvider = new Mock <IServiceProvider>();

            mockProvider.Setup(p => p.GetService(typeof(TraceHeaderContext))).Returns(context);
            mockProvider.Setup(p => p.GetService(typeof(IManagedTracerFactory))).Returns(tracerFactoryMock.Object);

            var tracer = CloudTraceExtension.CreateManagedTracer(mockProvider.Object);

            Assert.IsType(typeof(NullManagedTracer), tracer);
            tracerFactoryMock.VerifyAll();
            mockProvider.VerifyAll();
        }
コード例 #12
0
        public async Task Logging_Trace()
        {
            string   traceId   = "105445aa7843bc8bf206b12000100f00";
            string   testId    = Utils.GetTestId();
            DateTime startTime = DateTime.UtcNow;

            var builder = new WebHostBuilder().UseStartup <NoBufferWarningLoggerTestApplication>();

            using (var server = new TestServer(builder))
                using (var client = server.CreateClient())
                {
                    client.DefaultRequestHeaders.Add(TraceHeaderContext.TraceHeader,
                                                     TraceHeaderContext.Create(traceId, 81237123, null).ToString());
                    await client.GetAsync($"/Main/Critical/{testId}");

                    var results = _polling.GetEntries(startTime, testId, 1, LogSeverity.Critical);
                    Assert.Contains(Utils.GetProjectIdFromEnvironment(), results.Single().Trace);
                    Assert.Contains(traceId, results.Single().Trace);
                }
        }
コード例 #13
0
        public void CreateManagedTracer()
        {
            var accessor = new HttpContextAccessor();

            accessor.HttpContext = new DefaultHttpContext();
            var context           = TraceHeaderContext.Create(null, null, false);
            var tracerFactoryMock = new Mock <IManagedTracerFactory>();

            tracerFactoryMock.Setup(f => f.CreateTracer(context)).Returns(NullManagedTracer.Instance);
            var mockProvider = new Mock <IServiceProvider>();

            mockProvider.Setup(p => p.GetService(typeof(TraceHeaderContext))).Returns(context);
            mockProvider.Setup(p => p.GetService(typeof(IManagedTracerFactory))).Returns(tracerFactoryMock.Object);
            mockProvider.Setup(p => p.GetService(typeof(IHttpContextAccessor))).Returns(accessor);

            var tracer = CloudTraceExtension.CreateManagedTracer(mockProvider.Object);

            Assert.IsType(typeof(NullManagedTracer), tracer);
            Assert.Equal(tracer, accessor.HttpContext.Items[CloudTraceExtension.TraceKey]);
            tracerFactoryMock.VerifyAll();
            mockProvider.VerifyAll();
        }
コード例 #14
0
        /// <summary>
        /// Propagates Google trace context information to the response.
        /// Used by default if user code has not specified a propagator of their own.
        /// </summary>
        internal static void PropagateGoogleTraceHeaders(HttpResponse response, ITraceContext traceContext)
        {
            var googleHeader = TraceHeaderContext.Create(traceContext.TraceId, traceContext.SpanId ?? 0, traceContext.ShouldTrace);

            response.Headers.Add(TraceHeaderContext.TraceHeader, googleHeader.ToString());
        }
コード例 #15
0
 private static void GoogleTraceContextEmitter(HttpRequestHeaders headers, string traceId, ulong?spanId, bool?shouldTrace) =>
 // To mimic incoming requests with the Google trace header.
 headers.Add(TraceHeaderContext.TraceHeader, TraceHeaderContext.Create(traceId, spanId, shouldTrace).ToString());