Skip to content

Commit

Permalink
#145 adding env info endpoint, also adjusting content types on other …
Browse files Browse the repository at this point in the history
…endpoints
  • Loading branch information
alhardy committed May 27, 2017
1 parent 7a363cf commit 41655ce
Show file tree
Hide file tree
Showing 21 changed files with 299 additions and 35 deletions.
13 changes: 8 additions & 5 deletions sandbox/App.Metrics.Sandbox/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,15 @@ public void ConfigureServices(IServiceCollection services)

services.AddMetrics(Configuration.GetSection("AppMetrics")).
// AddJsonMetricsSerialization().
AddElasticsearchMetricsSerialization(ElasticSearchIndex).
// AddElasticsearchMetricsSerialization(ElasticSearchIndex).
AddJsonMetricsSerialization().
AddAsciiHealthSerialization().
// AddAsciiMetricsTextSerialization().
AddAsciiMetricsTextSerialization().
// AddPrometheusPlainTextSerialization().
AddInfluxDBLineProtocolMetricsTextSerialization().
AddReporting(
// AddInfluxDBLineProtocolMetricsTextSerialization().
// AddAsciiEnvironmentInfoSerialization().
AddJsonEnvironmentInfoSerialization().
AddReporting(
factory =>
{
if (ReportTypes.Any(r => r == ReportType.InfluxDB))
Expand Down Expand Up @@ -167,7 +170,7 @@ public void ConfigureServices(IServiceCollection services)
failing: value => (message: $"FAILED. 98th Percentile > 200ms ({value.Histogram.Percentile98}{SandboxMetricsRegistry.DatabaseTimer.DurationUnit.Unit()})", result: value.Histogram.Percentile98 > 200));
}).
AddMetricsMiddleware();
AddMetricsMiddleware(Configuration.GetSection("AspNetMetrics"));
}
}
}
2 changes: 2 additions & 0 deletions sandbox/App.Metrics.Sandbox/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@
"HealthEndpointEnabled": true,
"MetricsEndpointEnabled": true,
"MetricsTextEndpointEnabled": true,
"EnvironmentInfoEndpointEnabled": true,
"PingEndpointEnabled": true,
"OAuth2TrackingEnabled": true,
"HealthEndpoint": "/health",
"MetricsEndpoint": "/metrics",
"MetricsTextEndpoint": "/metrics-text",
"PingEndpoint": "/ping",
"EnvironmentInfoEndpoint": "/env",
"DefaultTrackingEnabled": true
},
"Logging": {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// <copyright file="IEnvironmentInfoResponseWriter.cs" company="Allan Hardy">
// Copyright (c) Allan Hardy. All rights reserved.
// </copyright>

using System.Threading;
using System.Threading.Tasks;
using App.Metrics.Infrastructure;
using Microsoft.AspNetCore.Http;

namespace App.Metrics.Extensions.Middleware.Abstractions
{
public interface IEnvironmentInfoResponseWriter
{
string ContentType { get; }

Task WriteAsync(HttpContext context, EnvironmentInfo environmentInfo, CancellationToken token = default(CancellationToken));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@ public static IApplicationBuilder UseMetrics(this IApplicationBuilder app)
var appMetricsOptions = app.ApplicationServices.GetRequiredService<AppMetricsOptions>();
var aspNetMetricsOptions = app.ApplicationServices.GetRequiredService<AspNetMetricsOptions>();

app.UseMiddleware<PingEndpointMiddleware>();
if (aspNetMetricsOptions.PingEndpointEnabled)
{
app.UseMiddleware<PingEndpointMiddleware>();
}

if (aspNetMetricsOptions.HealthEndpointEnabled)
{
Expand All @@ -61,6 +64,11 @@ public static IApplicationBuilder UseMetrics(this IApplicationBuilder app)
app.UseMiddleware<MetricsEndpointMiddleware>();
}

if (aspNetMetricsOptions.EnvironmentInfoEndpointEnabled)
{
app.UseMiddleware<EnvironmentInfoMiddleware>();
}

if (appMetricsOptions.MetricsEnabled && aspNetMetricsOptions.DefaultTrackingEnabled)
{
app.UseMiddleware<ActiveRequestCounterEndpointMiddleware>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public static IMetricsHostBuilder AddMetricsMiddleware(this IMetricsHostBuilder

private static IMetricsHostBuilder AddMetricsMiddlewareCore(this IMetricsHostBuilder builder)
{
builder.Services.TryAddSingleton<IEnvironmentInfoResponseWriter, NoOpEnvironmentInfoResponseWriter>();
builder.Services.TryAddSingleton<IMetricsResponseWriter, NoOpMetricsResponseWriter>();
builder.Services.TryAddSingleton<IMetricsTextResponseWriter, NoOpMetricsTextResponseWriter>();
builder.Services.TryAddSingleton<IHealthResponseWriter, NoOpHealthStatusResponseWriter>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public AspNetMetricsOptions()
MetricsEndpointEnabled = true;
MetricsTextEndpointEnabled = true;
PingEndpointEnabled = true;
EnvironmentInfoEndpointEnabled = true;
OAuth2TrackingEnabled = true;
ApdexTrackingEnabled = true;
ApdexTSeconds = Core.Internal.Constants.ReservoirSampling.DefaultApdexTSeconds;
Expand Down Expand Up @@ -134,13 +135,30 @@ public AspNetMetricsOptions()
/// </value>
public string PingEndpoint { get; set; } = Constants.DefaultRoutePaths.PingEndpoint.EnsureLeadingSlash();

/// <summary>
/// Gets or sets the environment info endpoint, defaults to /env.
/// </summary>
/// <value>
/// The environment info endpoint.
/// </value>
public string EnvironmentInfoEndpoint { get; set; } = Constants.DefaultRoutePaths.EnvironmentInfoEndpoint.EnsureLeadingSlash();

/// <summary>
/// Gets or sets a value indicating whether [ping endpoint should be enabled], if disabled endpoint responds with 404.
/// </summary>
/// <value>
/// <c>true</c> if [ping endpoint enabled]; otherwise, <c>false</c>.
/// </value>
public bool PingEndpointEnabled { get; set; }

/// <summary>
/// Gets or sets a value indicating whether [environment info endpoint should be enabled], if disabled endpoint
/// responds with 404.
/// </summary>
/// <value>
/// <c>true</c> if [environment info endpoint enabled]; otherwise, <c>false</c>.
/// </value>
public bool EnvironmentInfoEndpointEnabled { get; set; }
// ReSharper restore AutoPropertyCanBeMadeGetOnly.Global
// ReSharper restore CollectionNeverUpdated.Global
// ReSharper restore MemberCanBePrivate.Global
Expand Down
60 changes: 60 additions & 0 deletions src/App.Metrics.Extensions.Middleware/EnvironmentInfoMiddleware.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// <copyright file="EnvironmentInfoMiddleware.cs" company="Allan Hardy">
// Copyright (c) Allan Hardy. All rights reserved.
// </copyright>

using System;
using System.Net;
using System.Threading.Tasks;
using App.Metrics.Extensions.Middleware.Abstractions;
using App.Metrics.Extensions.Middleware.DependencyInjection.Options;
using App.Metrics.Infrastructure;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;

namespace App.Metrics.Extensions.Middleware
{
// ReSharper disable ClassNeverInstantiated.Global
public class EnvironmentInfoMiddleware : AppMetricsMiddleware<AspNetMetricsOptions>
// ReSharper restore ClassNeverInstantiated.Global
{
private readonly EnvironmentInfoProvider _environmentInfoProvider;
private readonly IEnvironmentInfoResponseWriter _environmentInfoResponseWriter;
private readonly RequestDelegate _next;

public EnvironmentInfoMiddleware(
RequestDelegate next,
AspNetMetricsOptions aspNetOptions,
ILoggerFactory loggerFactory,
IMetrics metrics,
IEnvironmentInfoResponseWriter environmentInfoResponseWriter,
EnvironmentInfoProvider environmentInfoProvider)
: base(next, aspNetOptions, loggerFactory, metrics)
{
_environmentInfoProvider = environmentInfoProvider;
_environmentInfoResponseWriter = environmentInfoResponseWriter ?? throw new ArgumentNullException(nameof(environmentInfoResponseWriter));
_next = next ?? throw new ArgumentNullException(nameof(next));
}

// ReSharper disable UnusedMember.Global
public async Task Invoke(HttpContext context)
// ReSharper restore UnusedMember.Global
{
if (Options.EnvironmentInfoEndpointEnabled && Options.EnvironmentInfoEndpoint.IsPresent() && Options.EnvironmentInfoEndpoint == context.Request.Path)
{
Logger.MiddlewareExecuting(GetType());

context.Response.Headers["Content-Type"] = new[] { _environmentInfoResponseWriter.ContentType };
context.SetNoCacheHeaders();
context.Response.StatusCode = (int)HttpStatusCode.OK;

await _environmentInfoResponseWriter.WriteAsync(context, _environmentInfoProvider.Build(), context.RequestAborted).ConfigureAwait(false);

Logger.MiddlewareExecuted(GetType());

return;
}

await _next(context);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public static class DefaultRoutePaths
public const string MetricsEndpoint = "/metrics";
public const string MetricsTextEndpoint = "/metrics-text";
public const string PingEndpoint = "/ping";
public const string EnvironmentInfoEndpoint = "/env";
}

public static class DefaultTagKeys
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// <copyright file="NoOpEnvironmentInfoResponseWriter.cs" company="Allan Hardy">
// Copyright (c) Allan Hardy. All rights reserved.
// </copyright>

using System.Threading;
using System.Threading.Tasks;
using App.Metrics.Core.Internal;
using App.Metrics.Extensions.Middleware.Abstractions;
using App.Metrics.Infrastructure;
using Microsoft.AspNetCore.Http;

namespace App.Metrics.Extensions.Middleware.Internal
{
[AppMetricsExcludeFromCodeCoverage]
internal class NoOpEnvironmentInfoResponseWriter : IEnvironmentInfoResponseWriter
{
/// <inheritdoc />
public string ContentType => "text/plain";

/// <inheritdoc />
public Task WriteAsync(HttpContext context, EnvironmentInfo environmentInfo, CancellationToken token = default(CancellationToken))
{
return context.Response.WriteAsync("No formatter has been registered. See App.Metrics.Formatters.Ascii for example.", token);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,17 @@ namespace App.Metrics.Extensions.Middleware
public class PingEndpointMiddleware : AppMetricsMiddleware<AspNetMetricsOptions>
// ReSharper restore ClassNeverInstantiated.Global
{
private readonly RequestDelegate _next;

public PingEndpointMiddleware(
RequestDelegate next,
AspNetMetricsOptions aspNetOptions,
ILoggerFactory loggerFactory,
IMetrics metrics)
: base(next, aspNetOptions, loggerFactory, metrics) { }
: base(next, aspNetOptions, loggerFactory, metrics)
{
_next = next ?? throw new ArgumentNullException(nameof(next));
}

// ReSharper disable UnusedMember.Global
public async Task Invoke(HttpContext context)
Expand All @@ -37,7 +42,7 @@ public async Task Invoke(HttpContext context)
return;
}

await Next(context);
await _next(context);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// <copyright file="AsciiEnvironmentInfoResponseWriter.cs" company="Allan Hardy">
// Copyright (c) Allan Hardy. All rights reserved.
// </copyright>

using System.Threading;
using System.Threading.Tasks;
using App.Metrics.Extensions.Middleware.Abstractions;
using App.Metrics.Formatting.Humanize;
using App.Metrics.Infrastructure;
using Microsoft.AspNetCore.Http;

namespace App.Metrics.Formatters.Ascii
{
public class AsciiEnvironmentInfoResponseWriter : IEnvironmentInfoResponseWriter
{
/// <inheritdoc />
public string ContentType => "text/plain; app.metrics=vnd.app.metrics.v1.environment.info;";

public Task WriteAsync(HttpContext context, EnvironmentInfo environmentInfo, CancellationToken token = default(CancellationToken))
{
return context.Response.WriteAsync(environmentInfo.Hummanize(), token);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace App.Metrics.Formatters.Ascii
public class AsciiHealthResponseWriter : IHealthResponseWriter
{
/// <inheritdoc />
public string ContentType => "text/vnd.app.metrics.v1.health+plain";
public string ContentType => "text/plain; app.metrics=vnd.app.metrics.v1.health;";

public Task WriteAsync(HttpContext context, HealthStatus healthStatus, CancellationToken token = default(CancellationToken))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace App.Metrics.Formatters.Ascii
public class AsciiMetricsResponseWriter : IMetricsResponseWriter
{
/// <inheritdoc />
public string ContentType => "text/vnd.app.metrics.v1.metrics+plain";
public string ContentType => "text/plain; app.metrics=vnd.app.metrics.v1.metrics;";

public Task WriteAsync(HttpContext context, MetricsDataValueSource metricsData, CancellationToken token = default(CancellationToken))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace App.Metrics.Formatters.Ascii
public class AsciiMetricsTextResponseWriter : IMetricsTextResponseWriter
{
/// <inheritdoc />
public string ContentType => "text/vnd.app.metrics.v1.metrics+plain";
public string ContentType => "text/plain; app.metrics=vnd.app.metrics.v1.metrics;";

public Task WriteAsync(HttpContext context, MetricsDataValueSource metricsData, CancellationToken token = default(CancellationToken))
{
Expand Down
21 changes: 17 additions & 4 deletions src/App.Metrics.Formatters.Ascii/MetricsHostExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,19 @@ namespace Microsoft.Extensions.DependencyInjection
public static class MetricsHostExtensions
{
/// <summary>
/// Enables Plain Text serialization on the health endpoint's response
/// Enables Plain Text serialization on the environment info endpoint's response
/// </summary>
/// <param name="host">The metrics host builder.</param>
/// <returns>The metrics host builder</returns>
public static IMetricsHostBuilder AddAsciiEnvironmentInfoSerialization(this IMetricsHostBuilder host)
{
host.Services.Replace(ServiceDescriptor.Transient<IEnvironmentInfoResponseWriter, AsciiEnvironmentInfoResponseWriter>());

return host;
}

/// <summary>
/// Enables Plain Text serialization on the health endpoint's response
/// </summary>
/// <param name="host">The metrics host builder.</param>
/// <returns>The metrics host builder</returns>
Expand All @@ -25,7 +37,7 @@ public static IMetricsHostBuilder AddAsciiHealthSerialization(this IMetricsHostB
}

/// <summary>
/// Enables Plain Text serialization on the metric endpoint's response
/// Enables Plain Text serialization on the metric endpoint's response
/// </summary>
/// <param name="host">The metrics host builder.</param>
/// <returns>The metrics host builder</returns>
Expand All @@ -37,7 +49,7 @@ public static IMetricsHostBuilder AddAsciiMetricsSerialization(this IMetricsHost
}

/// <summary>
/// Enables Plain Text serialization on the metric endpoint's response
/// Enables Plain Text serialization on the metric endpoint's response
/// </summary>
/// <param name="host">The metrics host builder.</param>
/// <returns>The metrics host builder</returns>
Expand All @@ -49,12 +61,13 @@ public static IMetricsHostBuilder AddAsciiMetricsTextSerialization(this IMetrics
}

/// <summary>
/// Enables Plain Text serialization on the metric and health endpoint responses
/// Enables Plain Text serialization on the metric and health endpoint responses
/// </summary>
/// <param name="host">The metrics host builder.</param>
/// <returns>The metrics host builder</returns>
public static IMetricsHostBuilder AddAsciiSerialization(this IMetricsHostBuilder host)
{
host.AddAsciiEnvironmentInfoSerialization();
host.AddAsciiHealthSerialization();
host.AddAsciiMetricsSerialization();
host.AddAsciiMetricsTextSerialization();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// <copyright file="IEnvironmentInfoSerializer.cs" company="Allan Hardy">
// Copyright (c) Allan Hardy. All rights reserved.
// </copyright>

namespace App.Metrics.Formatters.Json.Abstractions.Serialization
{
public interface IEnvironmentInfoSerializer
{
T Deserialize<T>(string value);

string Serialize<T>(T value);
}
}
Loading

0 comments on commit 41655ce

Please sign in to comment.