public void MultiThreading()
        {
            TraceIdentifiersContext c =
                new TraceIdentifiersContext(true, "qwe").LinkToSerilogLogContext(
                    builder => builder.WithDefaults());

            using (LogContext.PushProperty("anyOther", "Any1"))
                using (c)
                {
                    var logger = CreateLogger();
                    logger.Item1.Information("info1");

                    LogEvent logEvent = logger.Item3.Single(le => le.MessageTemplate.Text == "info1");
                    Assert.Equal(4, logEvent.Properties.Count);
                    Assert.Equal("Any1", logEvent.Properties["anyOther"].ToString().Trim('"'));
                    Assert.Equal(
                        TraceIdentifiersContext.StartupId,
                        logEvent.Properties["correlationStartup"].ToString().Trim('"'));
                    Assert.Equal("qwe", logEvent.Properties["correlationLocal"].ToString().Trim('"'));
                    Assert.Equal("[\"qwe\"]", logEvent.Properties["correlationAll"].ToString());
                    List <Thread> threads = new List <Thread>();
                    for (int i = 0; i < 1; i++)
                    {
                        Thread thread = new Thread(this.RunThread);
                        thread.Start(c);
                        threads.Add(thread);
                    }

                    foreach (Thread thread in threads)
                    {
                        thread.Join();
                    }
                }
        }
Beispiel #2
0
        private void RunThread(object state)
        {
            var logger = CreateLogger();

            logger.Item1.Information("info1");

            LogEvent logEvent = logger.Item3.Single(le => le.MessageTemplate.Text == "info1");

            Assert.Equal(5, logEvent.Properties.Count); // LogContext was able to survive thread switch
            TraceIdentifiersContext context = (TraceIdentifiersContext)state;
            string local = Thread.CurrentThread.ManagedThreadId.ToString("D");

            using (context.CloneForThread().CreateChildWithLocal(true, local))
            {
                logger.Item1.Information("info2");
                logEvent = logger.Item3.Single(le => le.MessageTemplate.Text == "info2");

                Assert.Equal(5, logEvent.Properties.Count);
                Assert.Equal("Any1", logEvent.Properties["anyOther"].ToString().Trim('"'));
                Assert.Equal(
                    TraceIdentifiersContext.StartupId,
                    logEvent.Properties["correlationStartup"].ToString().Trim('"'));
                Assert.Equal(local, logEvent.Properties["correlationLocal"].ToString().Trim('"'));
                Assert.Equal("rm", logEvent.Properties["correlationRemote"].ToString().Trim('"'));
                Assert.Equal($"[\"qwe\", \"{local}\"]", logEvent.Properties["correlationAll"].ToString());
            }
        }
Beispiel #3
0
        public void CreateOnSameLevel()
        {
            TraceIdentifiersContext c = new TraceIdentifiersContext(true, "qwe");

            c.CreateChildWithLocal(false, "1");
            Assert.Throws <InvalidOperationException>(() => c.CreateChildWithLocal(false, "2"));
        }
        private void ContextOnChildCreated(object sender, EventArgs e)
        {
            this.UpdateEnrichers();
            TraceIdentifiersContext child = (TraceIdentifiersContext)sender;

            child.Link(this); // Update enrichers after disposing child
        }
 public TraceIdentifiersEnricher(TraceIdentifiersContext context, LogContextBuilder builder)
 {
     Context = context ?? throw new ArgumentNullException(nameof(context));
     Builder = builder ?? throw new ArgumentNullException(nameof(builder));
     this.UpdateEnrichers();
     this.Context.OnChildCreated += ContextOnChildCreated;
 }
Beispiel #6
0
        private static void LinkEnrichersToContext(TraceIdentifiersContext context, LogContextBuilder builder)
        {
            TraceIdentifiersEnricher traceIdentifiersEnricher = new TraceIdentifiersEnricher(context, builder);
            IDisposable disposable = LogContext.Push(traceIdentifiersEnricher);

            context.Link(disposable);
        }
Beispiel #7
0
        public void CreateAndDisposeChilds()
        {
            TraceIdentifiersContext c = new TraceIdentifiersContext(true, "qwe");

            using (var c1 = c.CreateChildWithLocal(false, "c1"))
            {
                using (var c11 = c1.CreateChildWithLocal(false, "c11"))
                {
                    Assert.Equal("c11", c11.Local.ElementAt(0));
                    Assert.Equal("c1", c11.Local.ElementAt(1));
                    Assert.Equal("qwe", c11.Local.ElementAt(2));

                    Assert.Equal("c1", c1.Local.ElementAt(0));
                    Assert.Equal("qwe", c1.Local.ElementAt(1));

                    Assert.Equal("qwe", c.Local.ElementAt(0));
                }

                using (var c12 = c1.CreateChildWithLocal(false, "c12"))
                {
                    Assert.Equal("c12", c12.Local.ElementAt(0));
                    Assert.Equal("c1", c12.Local.ElementAt(1));
                    Assert.Equal("qwe", c12.Local.ElementAt(2));
                }
            }

            using (var c2 = c.CreateChildWithLocal(false, "c2"))
            {
                Assert.Equal("c2", c2.Local.ElementAt(0));
                Assert.Equal("qwe", c2.Local.ElementAt(1));
            }
        }
Beispiel #8
0
        public void AcceptRemotes()
        {
            TraceIdentifiersContext c = new TraceIdentifiersContext(true, "qwe");

            using (var c1 = c.CreateChildWithLocal(false, "c1"))
            {
                var r1 = c1.CreateChildWithRemote(new[] { "r1", "r2" });
                using (r1)
                {
                    Assert.Equal("c1", c1.Local.ElementAt(0));
                    Assert.Equal("qwe", c1.Local.ElementAt(1));

                    // Local saved if accept remote
                    Assert.Equal("c1", r1.Local.ElementAt(0));
                    Assert.Equal("qwe", r1.Local.ElementAt(1));

                    Assert.Equal("r1", r1.RemoteShared.ElementAt(0));
                    Assert.Equal("r2", r1.RemoteShared.ElementAt(1));

                    Assert.Equal("r1", c.RemoteShared.ElementAt(0));
                    Assert.Equal("r2", c1.RemoteShared.ElementAt(1));
                }

                Assert.Empty(r1.RemoteShared);

                Assert.Equal("c1", c1.Local.ElementAt(0));
                Assert.Equal("qwe", c1.Local.ElementAt(1));
                Assert.Empty(c.RemoteShared);
                Assert.Empty(c1.RemoteShared);
            }
        }
Beispiel #9
0
        public void CreateAndDisposeSingle()
        {
            TraceIdentifiersContext c1 = new TraceIdentifiersContext(true, "qwe");
            TraceIdentifiersContext c2 = new TraceIdentifiersContext(false, "qwe");

            using (c1)
                using (c2)
                {
                    Assert.Equal("qwe", Assert.Single(c1.Local));
                    Assert.Equal("qwe", Assert.Single(c1.LocalShared));

                    Assert.Equal("qwe", Assert.Single(c2.Local));
                    Assert.Empty(c2.LocalShared);
                }
        }
Beispiel #10
0
        public static TraceIdentifiersContext LinkToSerilogLogContext(
            this TraceIdentifiersContext traceIdentifiersContext, Action <LogContextBuilder> settings = null)
        {
            LogContextBuilder builder = new LogContextBuilder();

            settings?.Invoke(builder);

            LinkEnrichersToContext(traceIdentifiersContext, builder);

            traceIdentifiersContext.OnChildCreated += (sender, args) =>
            {
                TraceIdentifiersContext context = (TraceIdentifiersContext)sender;

                LinkEnrichersToContext(context, builder);
            };

            return(traceIdentifiersContext);
        }
        public void PushRemoteToContext()
        {
            TraceIdentifiersContext c =
                new TraceIdentifiersContext(true, "qwe")
                .LinkToSerilogLogContext(builder =>
                                         builder.WithStartup().WithRemoteIdentifiers());

            using (LogContext.PushProperty("anyOther", "Any1"))
                using (c)
                {
                    var logger = CreateLogger();
                    logger.Item1.Information("info1");

                    LogEvent logEvent = logger.Item3.Single(le => le.MessageTemplate.Text == "info1");
                    Assert.Equal(3, logEvent.Properties.Count);

                    Assert.Equal("Any1", logEvent.Properties["anyOther"].ToString().Trim('"'));
                    Assert.Equal(TraceIdentifiersContext.StartupId, logEvent.Properties["correlationStartup"].ToString().Trim('"'));
                    Assert.Equal("[]", logEvent.Properties["correlationRemoteAll"].ToString());

                    using (var r1 = c.CreateChildWithRemote(new [] { "r1", "r2" }))
                    {
                        logger.Item1.Information("info2");
                        logEvent = logger.Item3.Single(le => le.MessageTemplate.Text == "info2");
                        Assert.Equal(3, logEvent.Properties.Count);

                        Assert.Equal("Any1", logEvent.Properties["anyOther"].ToString().Trim('"'));
                        Assert.Equal(TraceIdentifiersContext.StartupId, logEvent.Properties["correlationStartup"].ToString().Trim('"'));
                        Assert.Equal("[\"r1\", \"r2\"]", logEvent.Properties["correlationRemoteAll"].ToString());

                        using (r1.CreateChildWithRemote(new[] { "r3", "r4" }))
                        {
                            logger.Item1.Information("info3");
                            logEvent = logger.Item3.Single(le => le.MessageTemplate.Text == "info3");
                            Assert.Equal(3, logEvent.Properties.Count);

                            Assert.Equal("Any1", logEvent.Properties["anyOther"].ToString().Trim('"'));
                            Assert.Equal(TraceIdentifiersContext.StartupId, logEvent.Properties["correlationStartup"].ToString().Trim('"'));
                            Assert.Equal("[\"r1\", \"r2\", \"r3\", \"r4\"]", logEvent.Properties["correlationRemoteAll"].ToString());
                        }
                    }
                }
        }
Beispiel #12
0
        public static IHttpClientBuilder SendTraceIdentifiersFromHttpContext(this IHttpClientBuilder builder, Action <HttpRequestMessage, TraceIdentifiersContext> setupIdentifiers = null)
        {
            builder.AddHttpMessageHandler(configureHandler: provider =>
            {
                IHttpContextAccessor httpContextAccessor = provider.GetRequiredService <IHttpContextAccessor>();
                TraceIdentifiersContext context          = httpContextAccessor.HttpContext.Features.Get <TraceIdentifiersContext>();

                if (setupIdentifiers == null)
                {
                    return(new SendIdentifiersDelegatingHandler(request =>
                                                                request.TryAddLocalSharedAndRemoteShared(context, SendIdentifiersOptions.Default)));
                }

                return(new SendIdentifiersDelegatingHandler(request =>
                                                            setupIdentifiers.Invoke(request, context)));
            });

            return(builder);
        }
Beispiel #13
0
        private static void LinkEnrichersToContext(TraceIdentifiersContext context, LogContextBuilder builder)
        {
            ILogEventEnricher[] enrichers = builder.Factories.Select(
                func =>
            {
                try
                {
                    return(func(context));
                }
                catch
                {
                    return(null);
                }
            }).Where(e => e != null).ToArray();

            if (enrichers.Any())
            {
                IDisposable disposable = LogContext.Push(enrichers);
                context.Link(disposable);
            }
        }
Beispiel #14
0
        public static TraceIdentifiersContext LinkToSerilogLogContext(
            this TraceIdentifiersContext context, Action <LogContextBuilder> settings = null)
        {
            LogContextBuilder builder = new LogContextBuilder();

            if (settings != null)
            {
                settings.Invoke(builder);
            }
            else
            {
                builder.WithDefaults();
            }

            LinkEnrichersToContext(context, builder);

            context.OnClonedForThread += (sender, args) =>
            {
                TraceIdentifiersContext newContext = (TraceIdentifiersContext)sender;
                LinkEnrichersToContext(newContext, builder);
            };

            return(context);
        }
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            // All identifiers contexts derived from this will have link with Serilog LogContext
            TraceIdentifiersContext.Startup.LinkToSerilogLogContext();

            app.UseTraceIdentifiers();

            app.MapWhen(context =>
                        context.Request.Path.StartsWithSegments(new PathString("/mvc"), StringComparison.OrdinalIgnoreCase),
                        builder => builder.UseMvcWithDefaultRoute());

            app.Run(async(context) =>
            {
                if (context.Request.Method != "GET")
                {
                    return;
                }
                await context.Response.WriteAsync("Hello World! ");
                TraceIdentifiersContext ti = context.Features.Get <TraceIdentifiersContext>();

                await context.Response.WriteAsync($"Startup: {TraceIdentifiersContext.StartupId}\n");
                await context.Response.WriteAsync($"Local: \n");
                foreach (string s in ti.Local)
                {
                    await context.Response.WriteAsync($"{s}\n");
                }

                await context.Response.WriteAsync($"RemoteShared: \n");
                foreach (string s in ti.RemoteShared)
                {
                    await context.Response.WriteAsync($"{s}\n");
                }

                context.RequestServices.GetRequiredService <ILoggerFactory>().CreateLogger("Demo").LogInformation("Hello World Log. correlationStartup: {correlationStartup} correlationLocal: {correlationLocal} correlationAll: {correlationAll}");

                if (!context.Request.Headers.ContainsKey(TraceIdentifiersDefaults.DefaultSharedHeaderName))
                {
                    System.Net.Http.HttpClient httpClient = new System.Net.Http.HttpClient();

                    string localhost = "http://localhost:65239/";

                    using (var c1 = ti.CreateChildWithLocal(true, "clientManual1"))
                    {
                        HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, localhost + "clientManual1");
                        request.TryAddLocalSharedAndRemoteShared(c1, SendIdentifiersOptions.Default);
                        HttpResponseMessage response = await httpClient.SendAsync(request);
                        string remoteSingle          = response.ReadRemoteIdentifier();

                        c1.CreateChildWithRemote(remoteSingle, false); //// not disposed but not shared, so available in logs only
                        await context.Response.WriteAsync($"\nResponse1: remote identifier: {remoteSingle}\n");
                        await context.Response.WriteAsync($"{await response.Content.ReadAsStringAsync()} \n");
                    }

                    using (var c2 = ti.CreateChildWithLocal(true, "clientManual2"))
                    {
                        HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, localhost + "clientManual2");
                        request.TryAddLocalSharedAndRemoteShared(c2, new SendIdentifiersOptions {
                            UseSeparator = true
                        });
                        HttpResponseMessage response = await httpClient.SendAsync(request);
                        string remoteSingle          = response.ReadRemoteIdentifier();
                        c2.CreateChildWithRemote(remoteSingle); // not disposed and shared, so will be propagated to all next requests and available in logs
                        await context.Response.WriteAsync($"\nResponse11: remote identifier: {remoteSingle}\n");
                        await context.Response.WriteAsync($"{await response.Content.ReadAsStringAsync()} \n");
                    }

                    httpClient =
                        context.RequestServices.GetRequiredService <IHttpClientFactory>().CreateClient("default");

                    using (ti.CreateChildWithLocal(true, "clientFromFactory"))
                    {
                        HttpResponseMessage response = await httpClient.GetAsync(localhost + "clientFromFactory");
                        string remoteSingle          = response.ReadRemoteIdentifier();

                        await context.Response.WriteAsync($"Response2: remote identifier: {remoteSingle} \n");
                        await context.Response.WriteAsync($"{await response.Content.ReadAsStringAsync()} \n");
                    }
                }
            });
        }
        private static IEnumerable <string> RemoteAllEscaped(LogContextBuilder builder, TraceIdentifiersContext c)
        {
            IEnumerable <string> remoteShared = c.Remote;

            if (builder.EscapeRemote)
            {
                remoteShared = remoteShared.Select(SecurityElement.Escape);
            }

            return(remoteShared);
        }
Beispiel #17
0
        public void PushLocalToContext()
        {
            TraceIdentifiersContext c =
                new TraceIdentifiersContext(true, "qwe").LinkToSerilogLogContext(builder => builder.WithStartup().WithLocalIdentifiers().WithLocalIdentifier());

            using (LogContext.PushProperty("anyOther", "Any1"))
                using (c)
                {
                    var logger = CreateLogger();
                    logger.Item1.Information("info1");

                    LogEvent logEvent = logger.Item3.Single(le => le.MessageTemplate.Text == "info1");
                    Assert.Equal(4, logEvent.Properties.Count);

                    Assert.Equal("Any1", logEvent.Properties["anyOther"].ToString().Trim('"'));
                    Assert.Equal(TraceIdentifiersContext.StartupId, logEvent.Properties["correlationStartup"].ToString().Trim('"'));
                    Assert.Equal("qwe", logEvent.Properties["correlationLocal"].ToString().Trim('"'));
                    Assert.Equal("[\"qwe\"]", logEvent.Properties["correlationLocalAll"].ToString());

                    using (var c1 = c.CreateChildWithLocal(false, "c1"))
                    {
                        logger.Item1.Information("info2");
                        logEvent = logger.Item3.Single(le => le.MessageTemplate.Text == "info2");
                        Assert.Equal(4, logEvent.Properties.Count);

                        Assert.Equal("Any1", logEvent.Properties["anyOther"].ToString().Trim('"'));
                        Assert.Equal(TraceIdentifiersContext.StartupId, logEvent.Properties["correlationStartup"].ToString().Trim('"'));
                        Assert.Equal("c1", logEvent.Properties["correlationLocal"].ToString().Trim('"'));
                        Assert.Equal("[\"qwe\", \"c1\"]", logEvent.Properties["correlationLocalAll"].ToString());

                        using (c1.CreateChildWithLocal(false, "c11"))
                        {
                            logger.Item1.Information("info3");
                            logEvent = logger.Item3.Single(le => le.MessageTemplate.Text == "info3");
                            Assert.Equal(4, logEvent.Properties.Count);

                            Assert.Equal("Any1", logEvent.Properties["anyOther"].ToString().Trim('"'));
                            Assert.Equal(TraceIdentifiersContext.StartupId, logEvent.Properties["correlationStartup"].ToString().Trim('"'));
                            Assert.Equal("c11", logEvent.Properties["correlationLocal"].ToString().Trim('"'));
                            Assert.Equal("[\"qwe\", \"c1\", \"c11\"]", logEvent.Properties["correlationLocalAll"].ToString());
                        }

                        using (c1.CreateChildWithLocal(false, "c12"))
                        {
                            logger.Item1.Information("info4");
                            logEvent = logger.Item3.Single(le => le.MessageTemplate.Text == "info4");
                            Assert.Equal(4, logEvent.Properties.Count);

                            Assert.Equal("Any1", logEvent.Properties["anyOther"].ToString().Trim('"'));
                            Assert.Equal(TraceIdentifiersContext.StartupId, logEvent.Properties["correlationStartup"].ToString().Trim('"'));
                            Assert.Equal("c12", logEvent.Properties["correlationLocal"].ToString().Trim('"'));
                            Assert.Equal("[\"qwe\", \"c1\", \"c12\"]", logEvent.Properties["correlationLocalAll"].ToString());
                        }
                    }

                    using (c.CreateChildWithLocal(false, "c2"))
                    {
                        logger.Item1.Information("info5");
                        logEvent = logger.Item3.Single(le => le.MessageTemplate.Text == "info5");
                        Assert.Equal(4, logEvent.Properties.Count);

                        Assert.Equal("Any1", logEvent.Properties["anyOther"].ToString().Trim('"'));
                        Assert.Equal(TraceIdentifiersContext.StartupId, logEvent.Properties["correlationStartup"].ToString().Trim('"'));
                        Assert.Equal("c2", logEvent.Properties["correlationLocal"].ToString().Trim('"'));
                        Assert.Equal("[\"qwe\", \"c2\"]", logEvent.Properties["correlationLocalAll"].ToString());
                    }

                    logger.Item1.Information("info6");
                    logEvent = logger.Item3.Single(le => le.MessageTemplate.Text == "info6");
                    Assert.Equal(4, logEvent.Properties.Count);

                    Assert.Equal("Any1", logEvent.Properties["anyOther"].ToString().Trim('"'));
                    Assert.Equal(TraceIdentifiersContext.StartupId, logEvent.Properties["correlationStartup"].ToString().Trim('"'));
                    Assert.Equal("qwe", logEvent.Properties["correlationLocal"].ToString().Trim('"'));
                    Assert.Equal("[\"qwe\"]", logEvent.Properties["correlationLocalAll"].ToString());
                }
        }