<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Logging &#8211; Cognim &#8211; Internet development</title>
	<atom:link href="https://www.cognim.co.uk/category/logging/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.cognim.co.uk</link>
	<description>Enterprise system implementation. Making the complex simple</description>
	<lastBuildDate>Thu, 14 Apr 2016 09:19:12 +0000</lastBuildDate>
	<language>en-GB</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	
<site xmlns="com-wordpress:feed-additions:1">91553907</site>	<item>
		<title>Modern Logging with SeriLog and Seq &#8211; part 2. Entry Point Logging</title>
		<link>https://www.cognim.co.uk/modern-logging-with-serilog-and-seq-part-2/</link>
					<comments>https://www.cognim.co.uk/modern-logging-with-serilog-and-seq-part-2/#comments</comments>
		
		<dc:creator><![CDATA[Darren Hall]]></dc:creator>
		<pubDate>Wed, 13 Apr 2016 13:02:26 +0000</pubDate>
				<category><![CDATA[c#]]></category>
		<category><![CDATA[Logging]]></category>
		<guid isPermaLink="false">http://www.cognim.co.uk/?p=5435</guid>

					<description><![CDATA[Entry Point Logging allows you to track all your API calls and the calls they make from a single place In the first part of this series I gave a brief overview of Serilog and Seq and what differentiates them from logging you may have done in the past.  One of the most useful aspects [&#8230;]]]></description>
										<content:encoded><![CDATA[<h3>Entry Point Logging allows you to track all your API calls and the calls they make from a single place</h3>
<p><a href="https://www.cognim.co.uk/modern-logging-serilog/" target="_blank">In the first part of this series I gave a brief overview of Serilog and Seq</a> and what differentiates them from logging you may have done in the past.  One of the most useful aspects of structured logging is the ability to trace the path of any particular call to your site, including key variables along the way. This post will explain how to set that up using Owin and middleware.</p>
<p>A key requirement in entry point logging is standardisation &#8211; all entry point logs should be generated by the same code if they are to be universally searchable (as well as being good SOLID practice!).</p>
<h4>Example</h4>
<p>Here is an example of a static entry point logger we are using, it is very simple code and uses the class SiteAccessDetails (which is added to our ClaimsPrincipal in middleware &#8211; <a href="https://www.cognim.co.uk/transforming-claims-claimsprincipal/">see this blog for details on how to do that</a>) to supply a shopName to be used as additional context.</p>
<pre class="lang:c# decode:true ">public static class EntryPointLogger
{
	public static IDisposable AddEntryPointContext(ILogger logger, SiteAccessDetails siteAccessDetails, string entryPointName)
	{
		var disposable = LogContext.PushProperty("HttpRequestId", Guid.NewGuid());

		if (!string.IsNullOrWhiteSpace(siteAccessDetails?.ShopName))
			LogContext.PushProperty("Shop", siteAccessDetails.ShopName);

		if (!string.IsNullOrWhiteSpace(entryPointName))
			LogContext.PushProperty("entryPointName", entryPointName);

		logger.Information("Entry Point: {entryPointName} called", entryPointName);

		return disposable;
	}

	public static IDisposable AddEntryPointContext(ILogger logger, string shopNameOrUrl, string entryPointName)
	{
		var userSiteDetails = new SiteAccessDetails(shopNameOrUrl, null, null);
		return AddEntryPointContext(logger, userSiteDetails, entryPointName);
	}

	public static IDisposable AddEntryPointContext(ILogger logger, string entryPointName)
	{
		return AddEntryPointContext(logger, (SiteAccessDetails)null, entryPointName);
	}
}</pre>
<p>We can call this manually from entry points in our code (Web API controllers etc) by adding a line like the following</p>
<pre class="lang:c# decode:true">var disposableLogContext = EntryPointLogger.AddEntryPointContext(logger, siteAccessDetails, "/api/customer/info");</pre>
<p>to the start of the controller action and</p>
<pre class="lang:c# decode:true ">disposableLogContext.Dispose();</pre>
<p>to the end, where logger has been defined in the constructor and passed in by IOC  or defined directly in the class as a private variable by using</p>
<pre class="lang:c# decode:true ">private readonly ILogger logger = Log.ForContext&lt;CustomerController&gt;();</pre>
<h4>Using Owin</h4>
<p>..but this means remembering to add it to every entry point that you create.  A better way if you are using Owin is to define a piece of middleware that calls it for you. Using the standard template for adding middleware&#8230;</p>
<pre class="lang:c# decode:true ">public class AppendEntryPointToSerilogContextMiddleware
{
	private readonly Func&lt;IDictionary&lt;string, object&gt;, Task&gt; _next;
	private readonly ILogger logger = Log.ForContext&lt;AppendEntryPointToSerilogContextMiddleware&gt;();

	public AppendEntryPointToSerilogContextMiddleware(Func&lt;IDictionary&lt;string, object&gt;, Task&gt; next)
	{
		_next = next;
	}

	public async Task Invoke(IDictionary&lt;string, object&gt; env)
	{
		var userSiteDetails = ClaimsPrincipal.Current.GetSiteDetails();
		object requestPath;
		env.TryGetValue("owin.RequestPath", out requestPath);

		using (EntryPointLogger.AddEntryPointContext(logger, userSiteDetails, requestPath?.ToString()))
		{
			await _next(env);
		}
}</pre>
<p>Which is invoked in the configuration method of your startup.cs class</p>
<pre class="lang:c# decode:true "> public void Configuration(IAppBuilder app)
{
  ...
  app.Use(typeof(AppendEntryPointToSerilogContextMiddleware));
  ...
}</pre>
<p>Notice that my code gets the site details from the ClaimsPrincipal as mentioned above and gets the path of the entry point from the Owin  RequestPath.</p>
<p>You will now get every call to your API fully logged with the path and in this case, the shop.</p>
<p>If you have entry points to your code that do not go through a request &#8211; we have subscriptions to an Azure Service Bus Topic for instance &#8211; you can just add the manual call to the entry point logger at the start.</p>
<h4>Try it!</h4>
<p>This is an extremely useful method for tracking live code which we now use extensively. If it has given you food for thought, give it a try, it&#8217;s really simple to use.</p>
<p>Get Serilog from here, get Seq from here</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.cognim.co.uk/modern-logging-with-serilog-and-seq-part-2/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">5435</post-id>	</item>
		<item>
		<title>Modern Logging with SeriLog and Seq</title>
		<link>https://www.cognim.co.uk/modern-logging-serilog/</link>
					<comments>https://www.cognim.co.uk/modern-logging-serilog/#comments</comments>
		
		<dc:creator><![CDATA[Darren Hall]]></dc:creator>
		<pubDate>Tue, 12 Apr 2016 15:28:39 +0000</pubDate>
				<category><![CDATA[c#]]></category>
		<category><![CDATA[Logging]]></category>
		<category><![CDATA[Seq]]></category>
		<category><![CDATA[Serilog]]></category>
		<guid isPermaLink="false">http://www.cognim.co.uk/?p=5419</guid>

					<description><![CDATA[Add structure to your log entries and bring your logs up to date It used to be that logging was a bit of an after thought where a few statements such as &#8216;Connecting to the database&#8217; or &#8216;Invalid user login&#8217; were written to a text file that was rarely looked at.  Well things have moved on a [&#8230;]]]></description>
										<content:encoded><![CDATA[<h3>Add structure to your log entries and bring your logs up to date</h3>
<p>It used to be that logging was a bit of an after thought where a few statements such as &#8216;Connecting to the database&#8217; or &#8216;Invalid user login&#8217; were written to a text file that was rarely looked at.  Well things have moved on a fair bit since then.</p>
<p>Part 1 of 2.  <a href="https://www.cognim.co.uk/modern-logging-with-serilog-and-seq-part-2/">Go here for part 2</a></p>
<h4>Serilog and Seq</h4>
<p><a href="http://serilog.net/" target="_blank">Serilog</a> is a modern structured logging solution that allows you to add context to your logs so that you can easily track a particular execution path.  <a href="https://getseq.net/" target="_blank">Seq</a> (pronounced &#8216;seek&#8217;) gives you the ability to host, display and search those logs.</p>
<p>For instance, imagine a customer calling and saying that when they log into your swanky portal and go to their profile page they don&#8217;t see their address.  With structured logging you could easily highlight all the logged api calls <em>made by that customer</em>, filter to the profile page and follow the execution path through to the address query to see the actual data returned.</p>
<h4>So simple!</h4>
<p>To add a context to Serilog and log to it, you just use</p>
<pre class="lang:c# decode:true">LogContext.PushProperty("customerName", customerName);</pre>
<p>Any further logging will now happen in that context, such as</p>
<pre class="lang:c# decode:true ">logger.Information("Getting customer profile");
...
logger.Information("Customer address: {customerAddress}", customerAddress);</pre>
<p>These two informational logs will now be tagged with the customer name. Notice also how Serilog uses a format similar to C# 6.0 string interpolation to embed variables. Doing it this way means you can filter by the variable in your logs.</p>
<h4>An example</h4>
<p>Here is a snapshot of a single log entry on our Seq server.</p>
<div id="attachment_5421" style="width: 731px" class="wp-caption aligncenter"><a href="https://i0.wp.com/www.cognim.co.uk/wp-content/uploads/2016/04/SeqTag.png?ssl=1" rel="attachment wp-att-5421"><img data-recalc-dims="1" decoding="async" aria-describedby="caption-attachment-5421" loading="lazy" class="wp-image-5421 size-full" src="https://i0.wp.com/www.cognim.co.uk/wp-content/uploads/2016/04/SeqTag.png?resize=721%2C135&#038;ssl=1" alt="Seq and Serilog structured logging" width="721" height="135" srcset="https://i0.wp.com/www.cognim.co.uk/wp-content/uploads/2016/04/SeqTag.png?w=721&amp;ssl=1 721w, https://i0.wp.com/www.cognim.co.uk/wp-content/uploads/2016/04/SeqTag.png?resize=300%2C56&amp;ssl=1 300w" sizes="auto, (max-width: 721px) 100vw, 721px" /></a><p id="caption-attachment-5421" class="wp-caption-text">A seq view of a serilog entry, highlighting the use of a tagged context.</p></div>
<p>It is from a system we created to track users through online shops and it highlights several things;</p>
<ul>
<li>We are logging the entry point of all our API calls</li>
<li>We have set tagging on Seq to display the entry point name at the beginning of the log entry (in this case it is &#8216;api/customers&#8217;) &#8211; this will then be displayed at the beginning of every subsequent log entry created during the execution of that particular api</li>
<li>We have assigned a unique id to every httpRequest that comes through which can also be tagged or filtered</li>
<li>We can also tag or filter by the Shop that was being tracked by the system</li>
</ul>
<p>If I tell Seq to limit the log display to only &#8216;api/customer&#8217; and also to filter by the httpRequestId I get the following (click to view full size);</p>
<div id="attachment_5422" style="width: 1034px" class="wp-caption aligncenter"><a href="https://i0.wp.com/www.cognim.co.uk/wp-content/uploads/2016/04/SeqFiltered.png?ssl=1" rel="attachment wp-att-5422"><img data-recalc-dims="1" decoding="async" aria-describedby="caption-attachment-5422" loading="lazy" class="wp-image-5422 size-large" src="https://i0.wp.com/www.cognim.co.uk/wp-content/uploads/2016/04/SeqFiltered.png?resize=1024%2C265&#038;ssl=1" alt="Serilog and Seq, context in use" width="1024" height="265" srcset="https://i0.wp.com/www.cognim.co.uk/wp-content/uploads/2016/04/SeqFiltered.png?resize=1024%2C265&amp;ssl=1 1024w, https://i0.wp.com/www.cognim.co.uk/wp-content/uploads/2016/04/SeqFiltered.png?resize=300%2C78&amp;ssl=1 300w, https://i0.wp.com/www.cognim.co.uk/wp-content/uploads/2016/04/SeqFiltered.png?resize=768%2C199&amp;ssl=1 768w, https://i0.wp.com/www.cognim.co.uk/wp-content/uploads/2016/04/SeqFiltered.png?w=1119&amp;ssl=1 1119w" sizes="auto, (max-width: 1000px) 100vw, 1000px" /></a><p id="caption-attachment-5422" class="wp-caption-text">Tracking the path of an api call through your code using Serilog and Seq</p></div>
<p>I can now see that the call to &#8216;customers/api&#8217; generated three further calls from our server to external apis (to our analytics server). Clicking on any of those will show me the details of the call or the response as we embedded the information in the log.</p>
<p>If I had instead chosen to tag and filter by the shop name I could see all activity related to a particular online shop.</p>
<p>What is great about this is how easy it is to quickly narrow down the exact log entries you are looking for and having done so, inspect the state of whatever variables you chose to embed in your log.</p>
<h4>Go try it yourself!</h4>
<p>I strongly recommend you to go and try out both Serilog and Seq.  <a href="https://www.cognim.co.uk/modern-logging-with-serilog-and-seq-part-2/">In the second part of this blog I show how we used Owin and middleware to create the entry point logging</a>.</p>
<p><a href="http://pluralsight.com/training/Courses/TableOfContents/modern-structured-logging-serilog-seq" target="_blank">If you want to know even more, take a look this Pluralsight course.</a></p>
<p>Have fun!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.cognim.co.uk/modern-logging-serilog/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">5419</post-id>	</item>
	</channel>
</rss>
