Created
October 16, 2013 06:30
-
-
Save abdullin/7003447 to your computer and use it in GitHub Desktop.
Simple azure log that persists sliding log buffer in Azure blobs.
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
using System; | |
using System.Collections.Concurrent; | |
using System.Collections.Generic; | |
using System.Threading; | |
using Microsoft.WindowsAzure; | |
using Microsoft.WindowsAzure.StorageClient; | |
namespace Lokad | |
{ | |
// Simple azure log that persists sliding log buffer in Azure blobs. | |
public class AzureLogSink | |
{ | |
/// <summary> | |
/// Enqueues a message into the logging queue | |
/// </summary> | |
/// <param name="fmt"></param> | |
/// <param name="fatal"></param> | |
/// <param name="ex"></param> | |
/// <param name="args"></param> | |
public void Log(string fmt, bool fatal = false, Exception ex = null, params object[] args) | |
{ | |
if (!_initialized) return; | |
_queue.Enqueue(new Entry | |
{ | |
IsError = fatal, | |
Args = args, | |
OptionalEx = ex, | |
Text = fmt | |
}); | |
} | |
sealed class Entry | |
{ | |
public string Text; | |
public bool IsError; | |
public Exception OptionalEx; | |
public object[] Args; | |
} | |
readonly ConcurrentQueue<Entry> _queue = new ConcurrentQueue<Entry>(); | |
readonly Thread _thread; | |
readonly bool _initialized; | |
readonly List<string> _traceBuffer = new List<string>(); | |
readonly List<string> _errorBuffer = new List<string>(); | |
readonly CloudBlob _traceBlob; | |
readonly CloudBlob _errorBlob; | |
public volatile int MaxLogSize = 5000; | |
void AppendEntryToBuffer(Entry e, IList<string> buffer) | |
{ | |
try | |
{ | |
var text = e.Text; | |
if (e.Args != null && e.Args.Length > 0) | |
{ | |
text = string.Format(text, e.Args); | |
} | |
buffer.Add(text); | |
if (e.OptionalEx != null) | |
{ | |
buffer.Add(e.OptionalEx.ToString()); | |
} | |
} | |
catch (Exception ex) | |
{ | |
buffer.Add(ex.ToString()); | |
} | |
while (buffer.Count > MaxLogSize) buffer.RemoveAt(0); | |
} | |
void KeepLogging() | |
{ | |
while (true) | |
{ | |
try | |
{ | |
var traceBufferChanged = false; | |
var errorBufferChanged = false; | |
Entry e; | |
while (_queue.TryDequeue(out e)) | |
{ | |
AppendEntryToBuffer(e, _traceBuffer); | |
traceBufferChanged = true; | |
if (e.IsError) | |
{ | |
AppendEntryToBuffer(e, _errorBuffer); | |
errorBufferChanged = true; | |
} | |
} | |
if (traceBufferChanged) | |
{ | |
DumpBuffer(_traceBuffer, _traceBlob); | |
} | |
if (errorBufferChanged) | |
{ | |
DumpBuffer(_errorBuffer, _errorBlob); | |
} | |
} | |
catch (Exception ex) | |
{ | |
System.Diagnostics.Trace.WriteLine(ex); | |
} | |
Thread.Sleep(TimeSpan.FromSeconds(2)); | |
} | |
} | |
static void DumpBuffer(IEnumerable<string> log, CloudBlob blob) | |
{ | |
blob.UploadText(string.Join(Environment.NewLine, log)); | |
} | |
public AzureLogSink(string connection, string errorFolder, string nodeType) | |
{ | |
var traceName = string.Format("{0:yyyy-MM-dd-HH-mm}-{1}-{2}.txt", DateTime.UtcNow, nodeType, Environment.MachineName); | |
var errorName = string.Format("{0:yyyy-MM-dd-HH-mm}-{1}-{2}-err.txt", DateTime.UtcNow, nodeType, Environment.MachineName); | |
try | |
{ | |
var client = CloudStorageAccount.Parse(connection).CreateCloudBlobClient(); | |
var container = client.GetContainerReference(errorFolder); | |
container.CreateIfNotExist(); | |
_traceBlob = container.GetBlobReference(traceName); | |
_errorBlob = container.GetBlobReference(errorName); | |
_thread = new Thread(KeepLogging) | |
{ | |
IsBackground = true | |
}; | |
_thread.Start(); | |
// we initialized properly | |
_initialized = true; | |
} | |
catch (Exception ex) | |
{ | |
System.Diagnostics.Trace.WriteLine(ex); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment