Skip to content

Instantly share code, notes, and snippets.

@philjhale
Created January 16, 2019 15:18
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 philjhale/5eea539ec7e83f9b4264e59e45848673 to your computer and use it in GitHub Desktop.
Save philjhale/5eea539ec7e83f9b4264e59e45848673 to your computer and use it in GitHub Desktop.
Serilog Humio HTTP sink
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Serilog.Events;
using Serilog.Formatting;
using Serilog.Sinks.PeriodicBatching;
namespace HumioHttpSink
{
/// <summary>
/// Based on this class https://gist.github.com/rasmuskl/b280b6fe4c6942ad6ec29244666cfc07
///
/// This class is a proof of concept and likely to be hilariously inefficient
/// </summary>
public class HumioHttpSink : PeriodicBatchingSink
{
private readonly string _ingestToken;
private readonly ITextFormatter _formatter;
private static readonly HttpClient HttpClient = new HttpClient();
private readonly Uri _uri;
public HumioHttpSink(string ingestToken, ITextFormatter formatter) : base(10, TimeSpan.FromSeconds(5))
{
_ingestToken = ingestToken;
_formatter = formatter;
_uri = new Uri(
"https://cloud.humio.com/api/v1/ingest/humio-structured");
}
protected override async Task EmitBatchAsync(IEnumerable<LogEvent> events)
{
try
{
/*
* Example structured payload. See ingest structured data docs https://docs.humio.com/api/ingest-api/#structured-data
*
* Required fields
* - At least one tag must be specified
* - Events require timestamp
*
* [
{
"tags": {
"host": "server1",
"source": "application.log"
},
"events": [
{
"timestamp": "2016-06-06T12:00:00+02:00",
"attributes": {
"key1": "value1",
"key2": "value2"
}
},
{
"timestamp": "2016-06-06T12:00:01+02:00",
"attributes": {
"key1": "value1"
}
}
]
}
]
*/
var eventsInHumioFormat = new List<object>();
foreach (var logEvent in events)
{
var sw = new StringWriter();
_formatter.Format(logEvent, sw);
var formattedLogEvent = JObject.Parse(sw.ToString());
eventsInHumioFormat.Add(new { timestamp = logEvent.Timestamp, attributes = formattedLogEvent});
}
// host and source tags should be altered to your needs
var payload = new[] { new { tags = new { host = "local", source = "ApplicationLog" }, events = eventsInHumioFormat } };
var jsonContent = JsonConvert.SerializeObject(payload);
var request = new HttpRequestMessage(HttpMethod.Post, _uri) { Content = new StringContent(jsonContent, Encoding.UTF8, "application/json") };
request.Headers.Add("Authorization", $"Bearer {_ingestToken}");
var response = await HttpClient.SendAsync(request);
if (response.StatusCode != HttpStatusCode.OK)
{
Console.WriteLine($"Failed to ship logs to Humio: {response.StatusCode} - {response.ReasonPhrase} - {await response.Content.ReadAsStringAsync()}");
}
}
catch (Exception e)
{
Console.WriteLine($"Failed to ship logs to Humio: {e}");
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment