Skip to content

Instantly share code, notes, and snippets.

@wgv-zbonham
Last active August 29, 2015 14:21
Show Gist options
  • Save wgv-zbonham/f8d607164f535505cf69 to your computer and use it in GitHub Desktop.
Save wgv-zbonham/f8d607164f535505cf69 to your computer and use it in GitHub Desktop.
Example Logging Using System.Diagnostics
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<system.diagnostics>
<sources>
<source name="WatchGuardLogging"
switchName="sourceSwitch"
switchType="System.Diagnostics.SourceSwitch">
<listeners>
<add name="WatchGuard"/>
<add name="EventLog"/>
</listeners>
</source>
<source name="WatchGuard.PackageLoader"
switchName="sourceSwitch"
switchType="System.Diagnostics.SourceSwitch">
<listeners>
<add name="WatchGuard"/>
</listeners>
</source>
</sources>
<sharedListeners>
<add name="WatchGuard" type="TickTickBoom.AzureStorageTraceListener, TickTickBoom" />
<add name="EventLog" type="System.Diagnostics.EventLogTraceListener" initializeData="Application"/>
</sharedListeners>
<switches>
<!-- this knob controls the logging level -->
<add name="sourceSwitch" value="Verbose"/>
</switches>
</system.diagnostics>
</configuration>
using System;
using System.Diagnostics;
using System.Text;
namespace TickTickBoom
{
public class AzureStorageTraceListener : TraceListener
{
public AzureStorageTraceListener()
{
// TODO - this needs to come from Role configuration
StorageConnectionString = "UseDevelopmentStorage=true";
}
public string StorageConnectionString { get; private set; }
public override void Write(string message)
{
Debug.Write(message);
}
public override void WriteLine(string message)
{
Debug.WriteLine(message);
}
/// <summary>
/// </summary>
/// <param name="eventCache"></param>
/// <param name="source"></param>
/// <param name="eventType"></param>
/// <param name="eventId"></param>
/// <param name="data"></param>
public override void TraceData(
TraceEventCache eventCache,
string source,
TraceEventType eventType,
int eventId,
object data)
{
var appEvent = data as AppEvent;
if (appEvent == null) return;
// TODO: write to Table Storage
// we are going to partition logs on daily boundary
var partitionKey = DateTime.Today.ToUniversalTime().Ticks.ToString();
// may want a better row key, or include more.
var rowKey = string.Format("{0}_{1}", partitionKey, Guid.NewGuid().ToString("N"));
var eventTick = DateTime.UtcNow.Ticks;
// TODO: get this from RoleEnvironment
var deploymentId = string.Empty;
var role = string.Empty;
var roleInstance = string.Empty;
Console.WriteLine(appEvent.Message);
}
}
public static class TraceSourceExtensions
{
public static void Debug(this TraceSource traceSource, string message, int eventId = 0, string detail = "")
{
WriteEvent(traceSource, TraceEventType.Verbose, message, eventId, detail);
}
public static void Info(this TraceSource traceSource, string message, int eventId = 0, string detail = "")
{
WriteEvent(traceSource, TraceEventType.Information, message, eventId, detail);
}
public static void Warn(this TraceSource traceSource, string message, int eventId = 0, string detail = "")
{
WriteEvent(traceSource, TraceEventType.Warning, message, eventId, detail);
}
public static void Error(this TraceSource traceSource, string message, int eventId = 0)
{
Error(traceSource, message, eventId, null);
}
public static void Error(this TraceSource traceSource, Exception eax)
{
Error(traceSource, eax.Message, 0, eax);
}
public static void Error(this TraceSource traceSource, string message, Exception eax)
{
Error(traceSource, message, 0, eax);
}
public static void Error(this TraceSource traceSource, string message, int eventId, Exception eax)
{
var detail = eax == null ? string.Empty : eax.ToString();
WriteEvent(traceSource, TraceEventType.Error, message, eventId, detail);
}
private static void WriteEvent(TraceSource traceSource, TraceEventType traceEventType, string message,
int eventId, string detail)
{
var appEvent = new AppEvent
{
Source = traceSource.Name,
EventId = eventId,
Level = (int) traceEventType,
Message = message,
Detail = detail
};
if (traceSource.Switch.ShouldTrace(traceEventType))
traceSource.TraceData(traceEventType, appEvent.EventId, appEvent);
}
}
public class AppEvent
{
/// <summary>
/// Unique instance id
/// </summary>
public Guid Id { get; set; }
/// <summary>
/// Integer representation of Error (3), Warning (3), Info (4), Verbose/Debug (16)
/// </summary>
public int Level { get; set; }
/// <summary>
/// EventId can be used to give specific event types an integer to pivot on
/// for monitoring and alerting decisions instead of having to read the message, or detail, to figure it out.
/// </summary>
public int EventId { get; set; }
/// <summary>
/// On premise, this is likely the Proces Name. On Azure, it will likely be Role Name.
/// </summary>
public string Source { get; set; }
/// <summary>
/// Something meaningful.
/// </summary>
public string Message { get; set; }
/// <summary>
/// Additional detail - could be a call stack for error, or message body if logging a request.
/// </summary>
public string Detail { get; set; }
/// <summary>
/// When did this event occur?
/// </summary>
public DateTime Timestamp { get; set; }
public override string ToString()
{
var sb = new StringBuilder();
sb.AppendLine(string.Format("Id: {0}", Id));
sb.AppendLine(string.Format("Source: {0}", Source));
sb.AppendLine(string.Format("Message: {0}", Message));
sb.AppendLine(string.Format("Detail: {0}", Detail));
return sb.ToString();
}
}
internal class Program
{
private static void Main(string[] args)
{
// Generally, a feature area will use the *same* SourceName. e.g. Mvc, WebApi, Worker, etc.
// You *can* have specific sources to specific activities but then we need to manage where they are stored
// so we can publish to operations
//
var logger = new TraceSource("WatchGuardLogging");
var packageSource = new TraceSource("WatchGuard.PackageLoader");
logger.Debug("This is a debug event");
logger.Info("This is an informational event");
logger.Warn("this is a warning event");
logger.Error("This is an error", 1000 );
logger.Error(new Exception("something wicked this way comes"));
var tenantId = Guid.NewGuid();
logger.Error(string.Format("Failed to connect to AD tenant {0}", tenantId),
new Exception("THis is really some specific connection/AD exception"));
packageSource.Debug("This is from package loader");
Console.ReadKey();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment