Skip to content

Instantly share code, notes, and snippets.

@abdullin
Created October 16, 2013 06:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save abdullin/7003447 to your computer and use it in GitHub Desktop.
Save abdullin/7003447 to your computer and use it in GitHub Desktop.
Simple azure log that persists sliding log buffer in Azure blobs.
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