{"id":138,"date":"2014-06-26T09:31:50","date_gmt":"2014-06-26T07:31:50","guid":{"rendered":"http:\/\/ingeniarius.net\/blog\/?p=138"},"modified":"2014-07-11T10:06:49","modified_gmt":"2014-07-11T08:06:49","slug":"logging-entity-framework-6-queries-to-azure-tables","status":"publish","type":"post","link":"https:\/\/ingeniarius.net\/blog\/2014\/06\/logging-entity-framework-6-queries-to-azure-tables\/","title":{"rendered":"Logging Entity Framework 6 queries to Azure Tables"},"content":{"rendered":"<p>I wrote about Semantic Logging (SL) in MVC and after watching <a title=\"Entity Framework: Building Applications with Entity Framework 6\" href=\"http:\/\/channel9.msdn.com\/events\/TechEd\/NorthAmerica\/2014\/DEV-B417#fbid=\" target=\"_blank\">Rowan Miller`s video from Tech Ed 2014 <\/a>I decided to implement logging Entity Framework 6 queries to Azure Tables with EventSource (aka Semantic Logging \/ Structured Logging).<\/p>\n<p>&nbsp;<\/p>\n<h2>Motivation for logging Entity Framework 6 queries to Azure Tables<\/h2>\n<p>By MHO the motivation behind every logging system must include :<\/p>\n<ol>\n<li>Finding and removing bugs which improves QoS and reduces Dev\/Ops time to resolve an issue.<\/li>\n<li>Good structured log which enables a less proficient programmers to solve the problem. Better support devs =&gt; higher ops. costs.<\/li>\n<li>Proactive response &#8211; get into action long before the client gets to you. Or even better &#8211; you call the client first.<\/li>\n<li>Measuring and optimizing performance of your app. <a href=\"http:\/\/channel9.msdn.com\/Events\/Build\/2014\/3-633\" target=\"_blank\">As Mark Simms and Chris Clayton say<\/a> that &#8220;<strong>premature optimization is the root of all evil.<\/strong>&#8221; is not so relevant when designing clod apps.<\/li>\n<\/ol>\n<p><!--more--><\/p>\n<h2><\/h2>\n<h2>Explanation<\/h2>\n<p>Why so much &#8220;maintenance cost&#8221;? Because &#8220;maintenance cost&#8221; is the source of most of the cost of a big app and lowering it as much as possible is a key feature. That is why I consider the logging to be a key feature for every working program. When you do not have good logging ( and documentation ) in case of a failure or a bug you have to rely on the knowledge, of the internals of the application, that is inside the head of a few (some times just one) of your best developers which will not be around for 15 years probably. And 10+ years is the minimum lifespan of enterprise apps that I have encountered so far &#8211; desktop or web based.<\/p>\n<p>What are the benefits of using EventSource for logging Entity Framework queries to Azure Tables compared to writing to file like in the video?<\/p>\n<p>Why I do not like the idea of a log.txt?<\/p>\n<ol>\n<li>Writing to log.txt places a file on each instance which makes it troublesome to get all the files from all instances and then combine them.<\/li>\n<li>You have to first combine all the files from all your instances before you even start searching for particular queries.<\/li>\n<li>You do not have structured logs but a bulk of text which makes searching cumbersome.<\/li>\n<li>Searching through big txt log files is not a pleasure at all &#8211; wastes time of the administrator\/developer\/ops guy.<\/li>\n<li>You have to do this every time you want to get all the logs and search for a problem or else.<\/li>\n<li>You can not easily <span style=\"font-family: Verdana, sans-serif; text-align: justify;\">start SQL Profiler on Web Role. (On all your web roles? :))<\/span><\/li>\n<li>I have personally used NLog for logging with a txt for web apps but when you go to multiple instances with great volume &#8211; it starts to become a burden rather then help.<\/li>\n<\/ol>\n<p>Why I do like the idea of EventSource (ETW) with Azure Tables?<\/p>\n<ol>\n<li>You have everything in one place right away.<\/li>\n<li>You have it structured. For example &#8211; InstanceId, Query, Time, etc, &#8230;. however you like it.<\/li>\n<li>You have tools to quickly and conveniently search Azure Tables. My favorite is<a href=\"http:\/\/www.cerebrata.com\/products\/azure-management-studio\/introduction\" target=\"_blank\"> Cerebrata\/RegGate Azure Management Studio<\/a>. But there are others free alternatives like <a href=\"http:\/\/azurestorageexplorer.codeplex.com\/\" target=\"_blank\">Azure Storage Explorer<\/a><\/li>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.diagnostics.tracing.eventsource%28v=vs.110%29.aspx\" target=\"_blank\">EventSource uses ETW<\/a> which is asynchronous and very fast. Why bother about that? Watch this video where\u00a0<a href=\"http:\/\/channel9.msdn.com\/Events\/Build\/2014\/3-633\" target=\"_blank\">Mark Simms and Chris Clayton<\/a> explain such a case where the synchrony of the logging framework was overlooked. Simms advises against Log4Net or other logging libraries which can not log asynchronously.<\/li>\n<li>If you use separate storage account for diagnostics (aka logging) you will hardly hit the limit of Azure Table &#8211; <a href=\"http:\/\/ppe.blogs.msdn.com\/b\/windowsazure\/archive\/2012\/11\/02\/windows-azure-s-flat-network-storage-and-2012-scalability-targets.aspx\">up to 20,000 per second.<\/a><\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<h2>Implementation<\/h2>\n<p>Without further ado lets get to the code.<\/p>\n<p>First the not so interesting part &#8211; The DbContext and DbSets to work with :<\/p>\n<pre class=\"lang:c# decode:true\" title=\"The DbContext and DbSets to work with\">public class ProductContext : DbContext\r\n{\r\n    public DbSet&lt;Category&gt; Categories { get; set; }\r\n    public DbSet&lt;Product&gt; Products { get; set; }\r\n    public DbSet&lt;Supplier&gt; Suppliers { get; set; }\r\n}\r\n\r\npublic class Category\r\n{\r\n   public int CategoryId { get; set; }\r\n   public string Name { get; set; }\r\n\r\n   public virtual ICollection&lt;Product&gt; Products { get; set; }\r\n}\r\n\r\npublic class Product\r\n{\r\n    public int ProductId { get; set; }\r\n    public string Name { get; set; }\r\n    public int CategoryId { get; set; }\r\n    public virtual Category Category { get; set; }\r\n}\r\n\r\npublic class Supplier\r\n{\r\n   [Key]\r\n   public string SupplierCode { get; set; }\r\n   public string Name { get; set; }\r\n}<\/pre>\n<p>Now the logger itself :<\/p>\n<pre class=\"lang:c# decode:true\" title=\"Entity Framework Logger with its interface\">public class EfLogger : EventSource, IEfLogger\r\n{\r\n    public static class Keywords\r\n    {\r\n        \/\/ only powers of 2 -&gt; 1,2,4,8,16,32,64,128\r\n        public const EventKeywords All = (EventKeywords)2048;\r\n    }\r\n\r\n    public void LogQuery(string query)\r\n    {\r\n        LogQueryInternal(query);\r\n    }\r\n\r\n    [Event(100, Keywords = Keywords.All,Level = EventLevel.LogAlways)]\r\n    private void LogQueryInternal(string query)\r\n    {\r\n        if (this.IsEnabled())\r\n        {\r\n                WriteEvent(100, query);\r\n        }\r\n    }\r\n}\r\n\r\npublic interface IEfLogger\r\n{\r\n    void LogQuery(string query);\r\n}<\/pre>\n<p>Why bother with the interface? You are probably going to drop it via <a href=\"http:\/\/www.manning.com\/seemann\/\">DI<\/a> into your DbContext builder. I still have doubts about how to implement logging because it is a <a href=\"http:\/\/www.manning.com\/seemann\/\">cross cutting concern as explained by M. Seeman in his book<\/a>: Drop it in over DI? Hide it behind static method? Mark the class with some <a href=\"http:\/\/blog.ploeh.dk\/2014\/06\/13\/passive-attributes\/\">passive attribute<\/a>? Implement it as a <a href=\"http:\/\/kozmic.net\/dynamic-proxy-tutorial\/\">Castle Windsor Dynamic Proxy Interceptor<\/a>? It depends on the app \ud83d\ude42<\/p>\n<p>Now the logger setup :<\/p>\n<pre class=\"lang:c# decode:true\">public class LoggerContainer\r\n{\r\n   private static readonly List&lt;EventListener&gt; Listeners = new List&lt;EventListener&gt;();\r\n\r\n    public static void SetupEntityFrameworkListener(IEfLogger efLogger)\r\n    {\r\n        try\r\n        {\r\n            EventSourceAnalyzer.InspectAll((EventSource)efLogger);\r\n        }\r\n        catch (EventSourceAnalyzerException eventSourceAnalyzerException)\r\n        {\r\n            string errorMsg = string.Format(\r\n                        \"Critical configuration error during event sources inspection. Exception Message : {0} StackTrace :{1} \",\r\n                        eventSourceAnalyzerException.Message,\r\n                        eventSourceAnalyzerException.StackTrace);\r\n            EventLog.WriteEntry(\"Event Sources Initialization\", errorMsg, EventLogEntryType.Error);\r\n        }\r\n        var listener = WindowsAzureTableLog.CreateListener(\r\n\"EfLog\",  \r\nConfigurationSettings.AppSettings[\"DiagnosticsConnectionString\"],\r\n\"EfLog\"\r\n);\r\n        Listeners.Add(listener);\r\n\r\n        listener.EnableEvents(\r\n            (EventSource)efLogger,\r\n            EventLevel.Informational,\r\n            EfLogger.Keywords.All);\r\n    }\r\n\r\n    public static void DisposeEventListener()\r\n    {\r\n        foreach (var eventListener in Listeners)\r\n        {\r\n           eventListener.Dispose();\r\n        }\r\n    }\r\n}<\/pre>\n<p>Now a screenshot of the results :<\/p>\n<figure id=\"attachment_165\" aria-describedby=\"caption-attachment-165\" style=\"width: 1637px\" class=\"wp-caption alignnone\"><a href=\"http:\/\/ingeniarius.net\/blog\/wp-content\/uploads\/2014\/06\/Cerebrata.Table_.Broser.EntityFramework.Log_.png\"><img decoding=\"async\" loading=\"lazy\" class=\"size-full wp-image-165\" src=\"http:\/\/ingeniarius.net\/blog\/wp-content\/uploads\/2014\/06\/Cerebrata.Table_.Broser.EntityFramework.Log_.png\" alt=\"Cerebrata Table Broser - EntityFramework Log\" width=\"1637\" height=\"648\" srcset=\"https:\/\/ingeniarius.net\/blog\/wp-content\/uploads\/2014\/06\/Cerebrata.Table_.Broser.EntityFramework.Log_.png 1637w, https:\/\/ingeniarius.net\/blog\/wp-content\/uploads\/2014\/06\/Cerebrata.Table_.Broser.EntityFramework.Log_-300x118.png 300w, https:\/\/ingeniarius.net\/blog\/wp-content\/uploads\/2014\/06\/Cerebrata.Table_.Broser.EntityFramework.Log_-1024x405.png 1024w\" sizes=\"(max-width: 1637px) 100vw, 1637px\" \/><\/a><figcaption id=\"caption-attachment-165\" class=\"wp-caption-text\">Cerebrata Table Broser &#8211; EntityFramework Log<\/figcaption><\/figure>\n<p>You can download the source code <a href=\"https:\/\/onedrive.live.com\/redir?resid=C3D1C9304A2004EC%2141327\" target=\"_blank\">here<\/a>. Do not forget to restore NuGet packages and build.<\/p>\n<p>&nbsp;<\/p>\n<h2>Resources<\/h2>\n<ol>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/data\/dn469464.aspx\" target=\"_blank\">http:\/\/msdn.microsoft.com\/en-us\/data\/dn469464.aspx<\/a><\/li>\n<li><a href=\"http:\/\/blog.oneunicorn.com\/2013\/05\/08\/ef6-sql-logging-part-1-simple-logging\/\" target=\"_blank\">http:\/\/blog.oneunicorn.com\/2013\/05\/08\/ef6-sql-logging-part-1-simple-logging\/<\/a><\/li>\n<li><a href=\"http:\/\/channel9.msdn.com\/Events\/Build\/2014\/3-633\" target=\"_blank\">http:\/\/channel9.msdn.com\/Events\/Build\/2014\/3-633<\/a><\/li>\n<li style=\"text-align: left;\"><a href=\"http:\/\/jpreecedev.com\/2013\/11\/13\/exploring-logging-in-entity-framework-6\/\" target=\"_blank\">http:\/\/jpreecedev.com\/2013\/11\/13\/exploring-logging-in-entity-framework-6\/<\/a><\/li>\n<li><a href=\"http:\/\/ppe.blogs.msdn.com\/b\/windowsazure\/archive\/2012\/11\/02\/windows-azure-s-flat-network-storage-and-2012-scalability-targets.aspx\" target=\"_blank\">http:\/\/ppe.blogs.msdn.com\/b\/windowsazure\/archive\/2012\/11\/02\/windows-azure-s-flat-network-storage-and-2012-scalability-targets.aspx<\/a><\/li>\n<li><a href=\"http:\/\/stackoverflow.com\/questions\/14443081\/azure-table-storage-transaction-limitations\" target=\"_blank\">http:\/\/stackoverflow.com\/questions\/14443081\/azure-table-storage-transaction-limitations<\/a><\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>I wrote about Semantic Logging (SL) in MVC and after watching Rowan Miller`s video from Tech Ed 2014 I decided to implement logging Entity Framework 6 queries to Azure Tables with EventSource (aka Semantic Logging \/ Structured Logging). &nbsp; Motivation for logging Entity Framework 6 queries to Azure Tables By MHO the motivation behind every&hellip; <a class=\"more-link\" href=\"https:\/\/ingeniarius.net\/blog\/2014\/06\/logging-entity-framework-6-queries-to-azure-tables\/\">Continue reading <span class=\"screen-reader-text\">Logging Entity Framework 6 queries to Azure Tables<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8,16,15],"tags":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/ingeniarius.net\/blog\/wp-json\/wp\/v2\/posts\/138"}],"collection":[{"href":"https:\/\/ingeniarius.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ingeniarius.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ingeniarius.net\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/ingeniarius.net\/blog\/wp-json\/wp\/v2\/comments?post=138"}],"version-history":[{"count":36,"href":"https:\/\/ingeniarius.net\/blog\/wp-json\/wp\/v2\/posts\/138\/revisions"}],"predecessor-version":[{"id":169,"href":"https:\/\/ingeniarius.net\/blog\/wp-json\/wp\/v2\/posts\/138\/revisions\/169"}],"wp:attachment":[{"href":"https:\/\/ingeniarius.net\/blog\/wp-json\/wp\/v2\/media?parent=138"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ingeniarius.net\/blog\/wp-json\/wp\/v2\/categories?post=138"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ingeniarius.net\/blog\/wp-json\/wp\/v2\/tags?post=138"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}