-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- SuperMassive.Logging : A logging library - SuperMassive.Logging.AzureTable : Logging library for Azure table Signed-off-by: PulsarBlow <pulsarblow@gmail.com>
- Loading branch information
1 parent
46d4697
commit bf668cf
Showing
32 changed files
with
5,303 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
using Microsoft.WindowsAzure.Storage.Table; | ||
|
||
namespace SuperMassive.Logging.AzureTable | ||
{ | ||
public class ApplicationLogEntity : TableEntity | ||
{ | ||
#region Properties | ||
/// <summary> | ||
/// ApplicationName | ||
/// </summary> | ||
public string ApplicationName { get; set; } | ||
/// <summary> | ||
/// EventId | ||
/// </summary> | ||
public int EventId { get; set; } | ||
/// <summary> | ||
/// Priority | ||
/// </summary> | ||
public int Priority { get; set; } | ||
/// <summary> | ||
/// Severity | ||
/// </summary> | ||
public string Severity { get; set; } | ||
/// <summary> | ||
/// Category | ||
/// </summary> | ||
public string Category { get; set; } | ||
/// <summary> | ||
/// Title | ||
/// </summary> | ||
public string Title { get; set; } | ||
/// <summary> | ||
/// MachineName | ||
/// </summary> | ||
public string MachineName { get; set; } | ||
/// <summary> | ||
/// AppDomainName | ||
/// </summary> | ||
public string AppDomainName { get; set; } | ||
/// <summary> | ||
/// ProcessId | ||
/// </summary> | ||
public string ProcessId { get; set; } | ||
/// <summary> | ||
/// ProcessName | ||
/// </summary> | ||
public string ProcessName { get; set; } | ||
/// <summary> | ||
/// ThreadName | ||
/// </summary> | ||
public string ThreadName { get; set; } | ||
/// <summary> | ||
/// Win32ThreadId | ||
/// </summary> | ||
public string Win32ThreadId { get; set; } | ||
/// <summary> | ||
/// Message | ||
/// </summary> | ||
public string Message { get; set; } | ||
/// <summary> | ||
/// FormattedMessage | ||
/// </summary> | ||
public string FormattedMessage { get; set; } | ||
#endregion | ||
} | ||
} |
122 changes: 122 additions & 0 deletions
122
Source/SuperMassive.Logging.AzureTable/ApplicationLogManager.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
using SuperMassive.Logging.Formatters; | ||
using System; | ||
using System.Diagnostics; | ||
using System.Globalization; | ||
|
||
namespace SuperMassive.Logging.AzureTable | ||
{ | ||
/// <summary> | ||
/// This class is responsible for managing <see cref="ApplicationLogEntity"/> in the system. | ||
/// </summary> | ||
public static class ApplicationLogEntityManager | ||
{ | ||
/// <summary> | ||
/// Returns a formatted row key | ||
/// </summary> | ||
/// <param name="sortOrder"></param> | ||
/// <returns></returns> | ||
public static string CreateRowKey(SortOrder sortOrder = SortOrder.Descending) | ||
{ | ||
return CreateRowKey(Guid.NewGuid(), DateTime.UtcNow, sortOrder); | ||
} | ||
|
||
/// <summary> | ||
/// Returns a formatted row key | ||
/// </summary> | ||
/// <param name="guid"></param> | ||
/// <returns></returns> | ||
public static string CreateRowKey(Guid guid, SortOrder sortOrder = SortOrder.Descending) | ||
{ | ||
return CreateRowKey(guid, DateTime.UtcNow, sortOrder); | ||
} | ||
|
||
/// <summary> | ||
/// Returns a formatted row key | ||
/// </summary> | ||
/// <param name="guid"></param> | ||
/// <param name="date"></param> | ||
/// <param name="sortOrder"></param> | ||
/// <returns></returns> | ||
public static string CreateRowKey(Guid guid, DateTime date, SortOrder sortOrder) | ||
{ | ||
long ticks = date.Ticks; | ||
if (sortOrder == SortOrder.Descending) | ||
ticks = DateTime.MaxValue.Ticks - date.Ticks; | ||
|
||
return String.Format(CultureInfo.InvariantCulture, "{0:D19}_{1}", ticks, guid.ToString()); | ||
} | ||
|
||
/// <summary> | ||
/// Returns a formatted partition key | ||
/// </summary> | ||
/// <param name="applicationName"></param> | ||
/// <param name="timeStamp"></param> | ||
/// <returns></returns> | ||
public static string CreatePartitionKey(string applicationName, DateTimeOffset timeStamp) | ||
{ | ||
Guard.ArgumentNotNullOrWhiteSpace(applicationName, "applicationName"); | ||
|
||
return String.Format(CultureInfo.InvariantCulture, "{0}_{1}", | ||
applicationName.Trim(), | ||
timeStamp.ToString("yyyyMM")); | ||
} | ||
|
||
/// <summary> | ||
/// Creates a full populated new <see cref="ApplicationLogEntity"/> from a given <see cref="LogEntry"/> | ||
/// </summary> | ||
/// <param name="logEntry"></param> | ||
/// <param name="formatter"></param> | ||
/// <returns></returns> | ||
public static ApplicationLogEntity CreateFromLogEntry(LogEntry logEntry, ILogFormatter formatter) | ||
{ | ||
Guard.ArgumentNotNull(logEntry, "logEntry"); | ||
ApplicationLogEntity entity = new ApplicationLogEntity | ||
{ | ||
AppDomainName = logEntry.AppDomainName, | ||
ApplicationName = logEntry.ApplicationName, | ||
Category = logEntry.Categories.Join(","), | ||
EventId = logEntry.EventId, | ||
MachineName = Environment.MachineName, | ||
Message = logEntry.Message, | ||
Priority = logEntry.Priority, | ||
ProcessId = logEntry.ProcessId, | ||
ProcessName = logEntry.ProcessName, | ||
Severity = logEntry.Severity.ToString(), | ||
ThreadName = logEntry.ManagedThreadName, | ||
Title = logEntry.Title, | ||
Win32ThreadId = logEntry.Win32ThreadId | ||
}; | ||
|
||
entity.Timestamp = new DateTimeOffset(logEntry.TimeStamp, TimeSpan.Zero); | ||
entity.PartitionKey = CreatePartitionKey(entity.ApplicationName, entity.Timestamp); | ||
entity.RowKey = ApplicationLogEntityManager.CreateRowKey(SortOrder.Descending); | ||
entity.FormattedMessage = formatter != null ? formatter.Format(logEntry) : logEntry.Message; | ||
|
||
return entity; | ||
} | ||
|
||
public static ApplicationLogEntity Create(string title, string rawMessage, string formattedMessage, int eventId, string applicationName = "Default", TraceEventType severity = TraceEventType.Error, string category = "General", int priority = 1, string processId = null, string processName = null, string threadName = null, string wind32ThreadId = null) | ||
{ | ||
return new ApplicationLogEntity | ||
{ | ||
AppDomainName = "Unknown AppDomain", | ||
ApplicationName = applicationName, | ||
Category = category, | ||
EventId = eventId, | ||
FormattedMessage = formattedMessage, | ||
MachineName = Environment.MachineName, | ||
Message = rawMessage, | ||
PartitionKey = CreatePartitionKey(applicationName, DateTimeOffset.UtcNow), | ||
Priority = priority, | ||
ProcessId = processId, | ||
ProcessName = processName, | ||
RowKey = ApplicationLogEntityManager.CreateRowKey(SortOrder.Descending), | ||
Severity = severity.ToString(), | ||
ThreadName = threadName, | ||
Timestamp = DateTimeOffset.UtcNow, | ||
Title = title, | ||
Win32ThreadId = wind32ThreadId | ||
}; | ||
} | ||
} | ||
} |
191 changes: 191 additions & 0 deletions
191
Source/SuperMassive.Logging.AzureTable/AzureTableFormattedTraceListener.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
using Microsoft.WindowsAzure.Storage; | ||
using Microsoft.WindowsAzure.Storage.Table; | ||
using SuperMassive.Logging.Formatters; | ||
using SuperMassive.Logging.TraceListeners; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Diagnostics; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace SuperMassive.Logging.AzureTable | ||
{ | ||
/// <summary> | ||
/// A <see cref="System.Diagnostics.TraceListener"/> that writes to a Cloud Storage, | ||
/// formatting the output with an <see cref="ILogFormatter"/>. | ||
/// </summary> | ||
public class FormattedAzureTableTraceListener : FormattedTraceListenerBase | ||
{ | ||
/// <summary> | ||
/// The name of the Azure Table where the log will be saved | ||
/// </summary> | ||
public const string DefaultAzureTableName = "ApplicationLogs"; | ||
|
||
/// <summary> | ||
/// The cloud storage connection string where to save the log to. | ||
/// </summary> | ||
protected string _cloudStorageConnectionString; | ||
|
||
/// <summary> | ||
/// The azure table storage name where to store traces | ||
/// </summary> | ||
protected string _azureTableName; | ||
|
||
/// <summary> | ||
/// Creates a new instance of the <see cref="FormattedAzureTableTraceListener"/> | ||
/// </summary> | ||
/// <param name="cloudStorageConnectionString"></param> | ||
public FormattedAzureTableTraceListener(string cloudStorageConnectionString) | ||
: this(cloudStorageConnectionString, DefaultAzureTableName, null) | ||
{ } | ||
|
||
/// <summary> | ||
/// Creates a new instance of the <see cref="FormattedAzureTableTraceListener"/> | ||
/// </summary> | ||
/// <param name="cloudStorageConnectionString"></param> | ||
/// <param name="azureTableName"></param> | ||
public FormattedAzureTableTraceListener(string cloudStorageConnectionString, string azureTableName) | ||
: this(cloudStorageConnectionString, azureTableName, null) | ||
{ } | ||
|
||
/// <summary> | ||
/// Creates a new instance of the <see cref="FormattedAzureTableTraceListener"/> | ||
/// </summary> | ||
/// <param name="cloudStorageConnectionString"></param> | ||
/// <param name="azureTaleName"></param> | ||
/// <param name="formatter"></param> | ||
public FormattedAzureTableTraceListener(string cloudStorageConnectionString, string azureTaleName, ILogFormatter formatter) | ||
: base(formatter) | ||
{ | ||
Guard.ArgumentNotNullOrWhiteSpace(cloudStorageConnectionString, "cloudStorageConnectionString"); | ||
Guard.ArgumentNotNullOrWhiteSpace(azureTaleName, "azureTableName"); | ||
_cloudStorageConnectionString = cloudStorageConnectionString; | ||
_azureTableName = azureTaleName; | ||
} | ||
|
||
/// <summary> | ||
/// Write a message | ||
/// </summary> | ||
/// <param name="message"></param> | ||
public override void Write(string message) | ||
{ | ||
LogEntry logEntry = CreateDefaultLogEntry(message); | ||
ExecuteWriteLog(logEntry); | ||
} | ||
|
||
/// <summary> | ||
/// Asynchronously write a message | ||
/// </summary> | ||
/// <param name="message"></param> | ||
/// <returns></returns> | ||
public async Task WriteAsync(string message) | ||
{ | ||
LogEntry logEntry = CreateDefaultLogEntry(message); | ||
await ExecuteWriteLogAsync(logEntry); | ||
} | ||
|
||
/// <summary> | ||
/// WriteLine | ||
/// </summary> | ||
/// <param name="message"></param> | ||
public override void WriteLine(string message) | ||
{ | ||
Write(message); | ||
} | ||
|
||
/// <summary> | ||
/// Asynchronous WriteLine | ||
/// </summary> | ||
/// <param name="message"></param> | ||
/// <returns></returns> | ||
public async Task WriteLineAsync(string message) | ||
{ | ||
await WriteAsync(message); | ||
} | ||
|
||
/// <summary> | ||
/// Trace data | ||
/// </summary> | ||
/// <param name="eventCache"></param> | ||
/// <param name="source"></param> | ||
/// <param name="eventType"></param> | ||
/// <param name="id"></param> | ||
/// <param name="data">Data to log. Can be a <see cref="String"/> or <see cref="LogEntry"/></param> | ||
public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id, object data) | ||
{ | ||
if (this.Filter == null || this.Filter.ShouldTrace(eventCache, source, eventType, id, null, null, data, null)) | ||
{ | ||
if (data is LogEntry) | ||
{ | ||
LogEntry logEntry = data as LogEntry; | ||
ExecuteWriteLog(logEntry); | ||
} | ||
else if (data is String) | ||
{ | ||
Write(data as String); | ||
} | ||
else | ||
{ | ||
base.TraceData(eventCache, source, eventType, id, data); | ||
} | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// CloudStorage write implementation | ||
/// </summary> | ||
/// <param name="logEntry"></param> | ||
protected void ExecuteWriteLog(LogEntry logEntry) | ||
{ | ||
ApplicationLogEntity entity = ApplicationLogEntityManager.CreateFromLogEntry(logEntry, this.Formatter); | ||
if (entity == null) | ||
return; | ||
|
||
CloudTable table = GetTableReference(); | ||
table.CreateIfNotExists(); | ||
TableOperation insertOperation = TableOperation.Insert(entity); | ||
table.Execute(insertOperation); | ||
} | ||
|
||
/// <summary> | ||
/// CloudStorage asynchronous write implementation | ||
/// </summary> | ||
/// <param name="logEntry"></param> | ||
/// <returns></returns> | ||
protected async Task ExecuteWriteLogAsync(LogEntry logEntry) | ||
{ | ||
ApplicationLogEntity entity = ApplicationLogEntityManager.CreateFromLogEntry(logEntry, this.Formatter); | ||
if (entity == null) | ||
return; | ||
|
||
CloudTable table = GetTableReference(); | ||
await table.CreateIfNotExistsAsync(); | ||
TableOperation insertOperation = TableOperation.Insert(entity); | ||
await table.ExecuteAsync(insertOperation); | ||
} | ||
|
||
/// <summary> | ||
/// Creates a default log entry | ||
/// </summary> | ||
/// <param name="message"></param> | ||
/// <returns></returns> | ||
protected virtual LogEntry CreateDefaultLogEntry(string message) | ||
{ | ||
return new LogEntry | ||
{ | ||
Severity = System.Diagnostics.TraceEventType.Information, | ||
TimeStamp = DateTime.UtcNow, | ||
Message = message, | ||
ApplicationName = "Undefined" | ||
}; | ||
} | ||
|
||
private CloudTable GetTableReference() | ||
{ | ||
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(_cloudStorageConnectionString); | ||
CloudTableClient tableClient = storageAccount.CreateCloudTableClient(); | ||
return tableClient.GetTableReference(DefaultAzureTableName); | ||
} | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
Source/SuperMassive.Logging.AzureTable/Properties/AssemblyInfo.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
using System.Reflection; | ||
using System.Runtime.InteropServices; | ||
|
||
|
||
[assembly: AssemblyTitle("SuperMassive.Logging.AzureTable")] | ||
[assembly: AssemblyDescription("Logging to Azure Table Storage")] | ||
[assembly: AssemblyCulture("")] | ||
[assembly: ComVisible(false)] | ||
[assembly: Guid("7cc4c6d3-f6b2-418b-87eb-2f9c8c33e83c")] |
Oops, something went wrong.