Browse Source

Datadog backported.

release/2.x
Sebastian 7 years ago
parent
commit
10bcf8f19c
  1. 82
      extensions/Squidex.Extensions/APM/Datadog/DatadogPlugin.cs
  2. 1
      extensions/Squidex.Extensions/Squidex.Extensions.csproj
  3. 15
      src/Squidex.Infrastructure/Log/Profiler.cs
  4. 69
      src/Squidex.Infrastructure/Log/ProfilerSpan.cs
  5. 6
      src/Squidex/appsettings.json

82
extensions/Squidex.Extensions/APM/Datadog/DatadogPlugin.cs

@ -0,0 +1,82 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using Datadog.Trace;
using Datadog.Trace.Configuration;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Squidex.Infrastructure.Log;
using Squidex.Infrastructure.Plugins;
namespace Squidex.Extensions.APM.Datadoq
{
public sealed class DatadogPlugin : IPlugin, IStartupFilter
{
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> nextBuilder)
{
return builder =>
{
builder.Use(async (context, next) =>
{
using (var scope = Tracer.Instance.StartActive(context.Request.Path))
{
try
{
scope.Span.SetTag("http.method", context.Request.Method);
await next();
}
catch (Exception ex)
{
scope.Span.SetException(ex);
throw;
}
finally
{
scope.Span.SetTag("http.status_code", context.Response.StatusCode.ToString());
}
}
});
nextBuilder(builder);
};
}
public void ConfigureServices(IServiceCollection services, IConfiguration config)
{
var isEnabled = config.GetValue<bool>("logging:datadog");
if (isEnabled)
{
services.AddSingleton<IStartupFilter>(this);
SetupTracer();
SetupProfiler();
}
}
private static void SetupProfiler()
{
Profiler.SpanStarted += session =>
{
session.Listen(Tracer.Instance.StartActive(session.Key));
};
}
private static void SetupTracer()
{
var settings = TracerSettings.FromDefaultSources();
settings.ServiceName = "squidex";
Tracer.Instance = new Tracer(settings);
}
}
}

1
extensions/Squidex.Extensions/Squidex.Extensions.csproj

@ -10,6 +10,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Algolia.Search" Version="5.3.1" /> <PackageReference Include="Algolia.Search" Version="5.3.1" />
<PackageReference Include="CoreTweet" Version="1.0.0.483" /> <PackageReference Include="CoreTweet" Version="1.0.0.483" />
<PackageReference Include="Datadog.Trace" Version="1.14.2" />
<PackageReference Include="Elasticsearch.Net" Version="6.7.0" /> <PackageReference Include="Elasticsearch.Net" Version="6.7.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="2.2.0" /> <PackageReference Include="Microsoft.Extensions.Http" Version="2.2.0" />
<PackageReference Include="Microsoft.OData.Core" Version="7.5.4" /> <PackageReference Include="Microsoft.OData.Core" Version="7.5.4" />

15
src/Squidex.Infrastructure/Log/Profiler.cs

@ -12,6 +12,8 @@ using Squidex.Infrastructure.Tasks;
namespace Squidex.Infrastructure.Log namespace Squidex.Infrastructure.Log
{ {
public delegate void ProfilerStarted(ProfilerSpan span);
public static class Profiler public static class Profiler
{ {
private static readonly AsyncLocal<ProfilerSession> LocalSession = new AsyncLocal<ProfilerSession>(); private static readonly AsyncLocal<ProfilerSession> LocalSession = new AsyncLocal<ProfilerSession>();
@ -22,6 +24,8 @@ namespace Squidex.Infrastructure.Log
get { return LocalSession.Value; } get { return LocalSession.Value; }
} }
public static event ProfilerStarted SpanStarted;
static Profiler() static Profiler()
{ {
Cleaner = new AsyncLocalCleaner<ProfilerSession>(LocalSession); Cleaner = new AsyncLocalCleaner<ProfilerSession>(LocalSession);
@ -60,14 +64,11 @@ namespace Squidex.Infrastructure.Log
return NoopDisposable.Instance; return NoopDisposable.Instance;
} }
var watch = ValueStopwatch.StartNew(); var span = new ProfilerSpan(session, key);
return new DelegateDisposable(() => SpanStarted?.Invoke(span);
{
var elapsedMs = watch.Stop();
session.Measured(key, elapsedMs); return span;
});
} }
} }
} }

69
src/Squidex.Infrastructure/Log/ProfilerSpan.cs

@ -0,0 +1,69 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Collections.Generic;
#pragma warning disable IDE0044 // Add readonly modifier
#pragma warning disable RECS0092 // Convert field to readonly
namespace Squidex.Infrastructure.Log
{
public sealed class ProfilerSpan : IDisposable
{
private readonly ProfilerSession session;
private readonly string key;
private ValueStopwatch watch = ValueStopwatch.StartNew();
private List<IDisposable> hooks;
public string Key
{
get { return key; }
}
public ProfilerSpan(ProfilerSession session, string key)
{
this.session = session;
this.key = key;
}
public void Listen(IDisposable hook)
{
Guard.NotNull(hook, nameof(hook));
if (hooks == null)
{
hooks = new List<IDisposable>(1);
}
hooks.Add(hook);
}
public void Dispose()
{
var elapsedMs = watch.Stop();
session.Measured(key, elapsedMs);
if (hooks != null)
{
for (var i = 0; i < hooks.Count; i++)
{
try
{
hooks[i].Dispose();
}
catch
{
continue;
}
}
}
}
}
}

6
src/Squidex/appsettings.json

@ -193,7 +193,11 @@
/* /*
* Set to true, to use colors. * Set to true, to use colors.
*/ */
"colors": true "colors": true,
/*
* True, to enable datadog integration.
*/
"datadog": false
}, },
"assetStore": { "assetStore": {

Loading…
Cancel
Save