Created
January 18, 2018 07:39
Hangfire stats collector Azure Function
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.Generic; | |
using System.Configuration; | |
using System.Globalization; | |
using System.Net.Http; | |
using System.Text; | |
using System.Threading.Tasks; | |
using Microsoft.Azure.WebJobs; | |
using Microsoft.Azure.WebJobs.Host; | |
using Flurl.Http; | |
using Microsoft.ApplicationInsights; | |
using Microsoft.ApplicationInsights.Extensibility; | |
using Newtonsoft.Json; | |
namespace HangfireStatsCollector | |
{ | |
public static class HangfireStatsCollector | |
{ | |
private static readonly string key; | |
private static readonly TelemetryClient telemetry; | |
static HangfireStatsCollector() | |
{ | |
key = ConfigurationManager.AppSettings["HangfireMetricsAppInsightsSinkKey"]; | |
if (!string.IsNullOrEmpty(key)) | |
{ | |
TelemetryConfiguration.Active.InstrumentationKey = key; | |
telemetry = new TelemetryClient() { InstrumentationKey = key }; | |
} | |
} | |
[FunctionName("HangfireStatsCollector")] | |
public static async Task Run( | |
[TimerTrigger("0 */1 * * * *", RunOnStartup = true)] TimerInfo myTimer, | |
TraceWriter log) | |
{ | |
log.Info($"C# Timer trigger function executed at: {DateTime.Now}"); | |
if (telemetry == null) | |
{ | |
log.Error("No App Insights instrumentation key available. Cannot publish metrics."); | |
return; | |
} | |
IList<string> paramsToFetch = new List<string> | |
{ | |
"enqueued:count-or-null", | |
"retries:count", | |
"recurring:count", | |
"servers:count", | |
"succeeded:count", | |
"failed:count" | |
}; | |
string ps = "metrics[]=" + string.Join("&metrics[]=", paramsToFetch); | |
string statsUrl = ConfigurationManager.AppSettings["HangfireStatsUrl"]; | |
if (string.IsNullOrEmpty(statsUrl)) | |
{ | |
log.Error("No Hangfire stats target URL specified. Cannot fetch metrics"); | |
return; | |
} | |
HangfireStatsWrapper stats; | |
try | |
{ | |
stats = | |
await statsUrl | |
.PostAsync( | |
new StringContent(ps, Encoding.UTF8, "application/x-www-form-urlencoded")) | |
.ReceiveJson<HangfireStatsWrapper>(); | |
} | |
catch (Exception e) | |
{ | |
log.Error("Unexpected exception", e); | |
telemetry.TrackException(e); | |
throw; | |
} | |
log.Info($"Got Hangfire stats: Succeeded = {stats.Succeeded.Value}, Retries = {stats.Retries.Value}, Failed = {stats.Failed.Value}"); | |
if (stats.Retries.ValueInt.HasValue) telemetry.TrackMetric("Hangfire-Retries", stats.Retries.ValueInt.Value); | |
if (stats.Succeeded.ValueInt.HasValue) telemetry.TrackMetric("Hangfire-Succeeded", stats.Succeeded.ValueInt.Value); | |
if (stats.Failed.ValueInt.HasValue) telemetry.TrackMetric("Hangfire-Failed", stats.Failed.ValueInt.Value); | |
if (stats.Servers.ValueInt.HasValue) telemetry.TrackMetric("Hangfire-Servers", stats.Servers.ValueInt.Value); | |
telemetry.Flush(); | |
} | |
} | |
public class HangfireStatsWrapper | |
{ | |
[JsonProperty("enqueued:count-or-null")] | |
public HangfireStat Enqueued { get; set; } | |
[JsonProperty("retries:count")] | |
public HangfireStat Retries { get; set; } | |
[JsonProperty("recurring:count")] | |
public HangfireStat Recurring { get; set; } | |
[JsonProperty("servers:count")] | |
public HangfireStat Servers { get; set; } | |
[JsonProperty("succeeded:count")] | |
public HangfireStat Succeeded { get; set; } | |
[JsonProperty("failed:count")] | |
public HangfireStat Failed { get; set; } | |
} | |
public class HangfireStat | |
{ | |
public string Value { get; set; } | |
[JsonIgnore] | |
public int? ValueInt | |
{ | |
get | |
{ | |
if (int.TryParse(Value, NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var valueResult)) | |
{ | |
return valueResult; | |
} | |
else | |
{ | |
return null; | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment