Skip to content

Instantly share code, notes, and snippets.

@CameronWills
Last active October 5, 2016 23:09
Show Gist options
  • Save CameronWills/0a7e4a8fc8ee9ede65a2cbaac9c0693c to your computer and use it in GitHub Desktop.
Save CameronWills/0a7e4a8fc8ee9ede65a2cbaac9c0693c to your computer and use it in GitHub Desktop.
A utility class to 'query' the application logs (System.Diagnostics.Trace) stored in Azure Blob storage - recursively descends log folder structure to find log files that match the requested date range and returns the nested log (.csv) files
/*
You will need to get install these two nuget libraries:
WindowsAzure.Storage
CsvHelper
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using CsvHelper;
using CsvHelper.Configuration;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Auth;
using Microsoft.WindowsAzure.Storage.Blob;
using Microsoft.WindowsAzure.Storage.RetryPolicies;
namespace AzureBlobLogQuery
{
public enum LogLevel
{
Verbose = 4,
Information = 3,
Warning = 2,
Error = 1
}
public class LogEntry
{
public DateTime Date { get; set; }
public LogLevel Level { get; set; }
public string ApplicationName { get; set; }
public string InstanceId { get; set; }
public long EventTickCount { get; set; }
public int Pid { get; set; }
public int Tid { get; set; }
public string Message { get; set; }
public string ActivityId { get; set; }
}
public class AzureBlobLogService
{
private const string logFileSuffix = ".applicationlog.csv";
private string containerName;
private CloudStorageAccount account;
private CloudBlobClient client;
private CloudBlobContainer container;
private string folderName;
public AzureBlobLogService(string accountName, string accountKey, string containerName, bool useHttps = true, string folderName = null)
{
this.containerName = containerName;
this.folderName = folderName;
this.account = new CloudStorageAccount(new StorageCredentials(accountName, accountKey), useHttps);
}
public IEnumerable<LogEntry> GetEntries(DateTime start, DateTime end, LogLevel level, string contains)
{
InitializeClient();
// Get top level directory
var topFolder = string.IsNullOrEmpty(folderName)
? container.ListBlobs().First() as CloudBlobDirectory
: container.GetDirectoryReference(folderName);
if (topFolder != null)
{
var filterContains = !string.IsNullOrWhiteSpace(contains);
var blobs = RecurseFolders(topFolder, start.ToString("yyyyMMddHH"), end.ToString("yyyyMMddHH"), string.Empty);
foreach (var blob in blobs)
{
using (var reader = new CsvReader(new StreamReader(blob.OpenRead()), new CsvConfiguration() { IsHeaderCaseSensitive = false }))
{
var entries = reader.GetRecords<LogEntry>().Reverse();
foreach (var entry in entries)
{
if (entry.Date >= start
&& entry.Date <= end
&& entry.Level <= level
&& (!filterContains || entry.Message.IndexOf(contains, StringComparison.OrdinalIgnoreCase) >= 0))
yield return entry;
}
}
}
}
yield break;
}
private IEnumerable<CloudBlob> RecurseFolders(CloudBlobDirectory folder, string start, string end, string current)
{
foreach (var child in folder.ListBlobs().Reverse())
{
if (current.Length < start.Length)
{
var childFolder = child as CloudBlobDirectory;
if (childFolder != null)
{
var name = GetName(childFolder);
var value = current + name;
int valueDate;
if (int.TryParse(value, out valueDate))
{
var startDate = int.Parse(start.Substring(0, value.Length));
var endDate = int.Parse(end.Substring(0, value.Length));
if (valueDate >= startDate && valueDate <= endDate)
{
var blobs = RecurseFolders(childFolder, start, end, value);
foreach (var blob in blobs)
yield return blob;
}
}
}
}
else
{
var blob = child as CloudBlob;
if (blob != null && blob.Name.ToLowerInvariant().EndsWith(logFileSuffix))
yield return blob;
}
}
}
private string GetName(CloudBlobDirectory folder)
{
var parts = folder.Prefix.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
return parts[parts.Length - 1];
}
private void InitializeClient()
{
if (client == null)
{
client = account.CreateCloudBlobClient();
client.DefaultRequestOptions.RetryPolicy = new LinearRetry(TimeSpan.FromSeconds(2), 3);
container = client.GetContainerReference(containerName);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment