Skip to content

Commit

Permalink
SPDBT-3022: added dynamics instrumentation (#1417)
Browse files Browse the repository at this point in the history
  • Loading branch information
ytqsl authored Sep 19, 2024
1 parent 80eae9e commit a626395
Show file tree
Hide file tree
Showing 15 changed files with 163 additions and 66 deletions.
13 changes: 7 additions & 6 deletions src/.dockerignore
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
# directories
**/bin/
**/obj/
**/out/
**/node_modules/
**/.angular/
**/bin
**/obj
**/out
**/node_modules
**/.angular
**/.vs

# files
*[Dd]ockerfile*
**/*.trx
**/*.md
**/*.ps1
**/*.cmd
**/*.sh
**/*.sh
5 changes: 2 additions & 3 deletions src/Spd.Presentation.Dynamics/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,17 @@
using System.Text.Json.Serialization;

var builder = WebApplication.CreateBuilder(args);
var assemblies = ReflectionExtensions.DiscoverLocalAessemblies(prefix: "Spd.");

var secretsFilePath = builder.Configuration.GetValue<string>("SECRETS_FILE");
if (!string.IsNullOrEmpty(secretsFilePath)) builder.Configuration.AddJsonFile(secretsFilePath, true, true);

var logger = builder.ConfigureWebApplicationObservability();
var logger = builder.ConfigureWebApplicationObservability(assemblies);

logger.Information("Starting up");

try
{
var assemblies = ReflectionExtensions.DiscoverLocalAessemblies(prefix: "Spd.");

builder.Services.ConfigureCors(builder.Configuration);
var assemblyName = $"{typeof(Program).Assembly.GetName().Name}";

Expand Down
2 changes: 0 additions & 2 deletions src/Spd.Presentation.Dynamics/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft ": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"System.Net.Http.HttpClient": "Warning",
"Microsoft.OData.Extensions.Client": "Warning"
}
Expand Down
5 changes: 2 additions & 3 deletions src/Spd.Presentation.Licensing/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,17 @@
using System.Text.Json.Serialization;

var builder = WebApplication.CreateBuilder(args);
var assemblies = ReflectionExtensions.DiscoverLocalAessemblies(prefix: "Spd.");

var secretsFilePath = builder.Configuration.GetValue<string>("SECRETS_FILE");
if (!string.IsNullOrEmpty(secretsFilePath)) builder.Configuration.AddJsonFile(secretsFilePath, true, true);

var logger = builder.ConfigureWebApplicationObservability();
var logger = builder.ConfigureWebApplicationObservability(assemblies);

logger.Information("Starting up");

try
{
var assemblies = ReflectionExtensions.DiscoverLocalAessemblies(prefix: "Spd.");

builder.Services.ConfigureCors(builder.Configuration);
var assemblyName = $"{typeof(Program).GetTypeInfo().Assembly.GetName().Name}";

Expand Down
5 changes: 3 additions & 2 deletions src/Spd.Presentation.Licensing/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
"Microsoft.AspNetCore": "Warning",
"System.Net.Http.HttpClient": "Warning",
"Microsoft.OData.Extensions.Client": "Warning"
}
}
},
Expand Down
5 changes: 2 additions & 3 deletions src/Spd.Presentation.Screening/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,17 @@
using System.Text.Json.Serialization;

var builder = WebApplication.CreateBuilder(args);
var assemblies = ReflectionExtensions.DiscoverLocalAessemblies(prefix: "Spd.");

var secretsFilePath = builder.Configuration.GetValue<string>("SECRETS_FILE");
if (!string.IsNullOrEmpty(secretsFilePath)) builder.Configuration.AddJsonFile(secretsFilePath, true, true);

var logger = builder.ConfigureWebApplicationObservability();
var logger = builder.ConfigureWebApplicationObservability(assemblies);

logger.Information("Starting up");

try
{
var assemblies = ReflectionExtensions.DiscoverLocalAessemblies(prefix: "Spd.");

builder.Services.ConfigureCors(builder.Configuration);
var assemblyName = $"{typeof(Program).GetTypeInfo().Assembly.GetName().Name}";

Expand Down
5 changes: 3 additions & 2 deletions src/Spd.Presentation.Screening/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
"Microsoft.AspNetCore": "Warning",
"System.Net.Http.HttpClient": "Warning",
"Microsoft.OData.Extensions.Client": "Warning"
}
}
},
Expand Down
4 changes: 3 additions & 1 deletion src/Spd.Utilities.Dynamics/Configurer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

namespace Spd.Utilities.Dynamics;

public class Configurer : IConfigureComponents
public class Configurer : IConfigureComponents, IProvideInstrumentationSources
{
public void Configure(ConfigurationContext configurationServices)
{
Expand Down Expand Up @@ -34,4 +34,6 @@ public void Configure(ConfigurationContext configurationServices)
services.AddSingleton<IDynamicsContextFactory, DynamicsContextFactory>();
services.AddTransient<DynamicsHealthCheck>();
}

public InstrumentationSources GetInstrumentationSources() => new InstrumentationSources { TraceSources = [DynamicsContext.ActivitySourceName] };
}
84 changes: 80 additions & 4 deletions src/Spd.Utilities.Dynamics/DynamicsContext.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,85 @@
namespace Spd.Utilities.Dynamics
using Microsoft.OData.Client;
using System.Diagnostics;
using System.Net;

namespace Spd.Utilities.Dynamics;

public class DynamicsContext : Microsoft.Dynamics.CRM.System, IDisposable
{
public class DynamicsContext : Microsoft.Dynamics.CRM.System
public static readonly string ActivitySourceName = typeof(DynamicsContext).FullName!;
private static ActivitySource source = new(ActivitySourceName);
private Activity? executionActivity;

private bool disposedValue;

public DynamicsContext(Uri serviceRoot) : base(serviceRoot)
{
public DynamicsContext(Uri serviceRoot) : base(serviceRoot)
this.SendingRequest2 += Instrument;
this.BuildingRequest += Instrument;
this.ReceivingResponse += Instrument;
}

private void Instrument(object? sender, ReceivingResponseEventArgs e)
{
if (executionActivity != null)
{
var tags = new ActivityTagsCollection
{
{ nameof(e.ResponseMessage.StatusCode), e.ResponseMessage.StatusCode }
};
if (e.Descriptor is EntityDescriptor ed)
{
tags.Add(nameof(EntityDescriptor.State), ed.State);
tags.Add(nameof(EntityDescriptor.Entity), ed.Entity?.GetType().Name);
}

executionActivity.AddEvent(new ActivityEvent(nameof(ReceivingResponse), tags: tags));
executionActivity.SetStatus(e.ResponseMessage.StatusCode != (int)HttpStatusCode.OK ? ActivityStatusCode.Error : ActivityStatusCode.Ok);
executionActivity.Stop();
}
}

private void Instrument(object? sender, BuildingRequestEventArgs e)
{
executionActivity = source.StartActivity(e.Method);
executionActivity?.SetTag(nameof(e.Method), e.Method);
}

private void Instrument(object? sender, SendingRequest2EventArgs e)
{
if (executionActivity != null)
{
var tags = new ActivityTagsCollection
{
{ nameof(e.IsBatchPart), e.IsBatchPart },
{ nameof(e.IsBulkUpdate), e.IsBulkUpdate },
{ nameof(e.RequestMessage.Url), e.RequestMessage.Url.ToString() }
};
if (e.Descriptor is EntityDescriptor ed)
{
tags.Add(nameof(EntityDescriptor.State), ed.State);
tags.Add(nameof(EntityDescriptor.Entity), ed.Entity?.GetType().Name);
}
executionActivity.AddEvent(new ActivityEvent(nameof(SendingRequest2), tags: tags));
}
}
}

protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
executionActivity?.Dispose();
}

disposedValue = true;
}
}

public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
17 changes: 17 additions & 0 deletions src/Spd.Utilities.Hosting/IProvideInstrumentationSources.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Spd.Utilities.Hosting;
public interface IProvideInstrumentationSources
{
InstrumentationSources GetInstrumentationSources();
}

public record InstrumentationSources
{
public IEnumerable<string> TraceSources { get; set; } = [];
}

28 changes: 16 additions & 12 deletions src/Spd.Utilities.Hosting/ObservabilityExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public static class ObservabilityExtensions
/// Configures observability instruments like logging to the web application and return an initial logger
/// </summary>
/// <returns>A logger that can be used during starting up the web application</returns>
public static ILogger ConfigureWebApplicationObservability(this WebApplicationBuilder builder, string? serviceName = null)
public static ILogger ConfigureWebApplicationObservability(this WebApplicationBuilder builder, IEnumerable<Assembly> discoveryAssemblies, string? serviceName = null)
{
Serilog.Debugging.SelfLog.Enable(Console.Error);
var logger = CreateBootstrapLogger(builder.Configuration);
Expand Down Expand Up @@ -69,12 +69,15 @@ public static ILogger ConfigureWebApplicationObservability(this WebApplicationBu

if (enableTracing)
{
var traceSources = discoveryAssemblies?.SelectMany(a => a.CreateInstancesOf<IProvideInstrumentationSources>()).Select(p => p.GetInstrumentationSources()).SelectMany(s => s.TraceSources).ToArray() ?? [];

builder.Services.AddOpenTelemetry()
.ConfigureResource(resource => resource.AddService(serviceName))
.WithTracing(tracing => tracing
.ConfigureResource(resource => resource.AddService(serviceName).AddEnvironmentVariableDetector())
.WithTracing(tracing => tracing
.AddAspNetCoreInstrumentation()
.AddRedisInstrumentation()
.AddHttpClientInstrumentation()
.AddSource(traceSources)
.AddOtlpExporter(opts =>
{
opts.Endpoint = new Uri(otelEndpoint, "/v1/traces");
Expand All @@ -91,15 +94,16 @@ public static ILogger ConfigureWebApplicationObservability(this WebApplicationBu
if (enableMetrics)
{
builder.Services.AddOpenTelemetry()
.WithMetrics(metrics => metrics
.AddAspNetCoreInstrumentation()
.AddRuntimeInstrumentation()
.AddHttpClientInstrumentation()
.AddOtlpExporter(opts =>
{
opts.Endpoint = new Uri(otelEndpoint, "/v1/metrics");
opts.Protocol = otelProtocol;
}));
.ConfigureResource(resource => resource.AddService(serviceName).AddEnvironmentVariableDetector())
.WithMetrics(metrics => metrics
.AddAspNetCoreInstrumentation()
.AddRuntimeInstrumentation()
.AddHttpClientInstrumentation()
.AddOtlpExporter(opts =>
{
opts.Endpoint = new Uri(otelEndpoint, "/v1/metrics");
opts.Protocol = otelProtocol;
}));
}
else
{
Expand Down
4 changes: 2 additions & 2 deletions tools/helm/charts/sparc/templates/_configmap.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ metadata:
name: {{ .name }}-files-configmap
labels: {{ .labels | nindent 4 }}
data:
{{- range $key, $value := .Values.files.files }}
{{ $key }}: |- {{ $.Files.Get $value | nindent 4 }}
{{- range $src, $dst := .Values.files }}
{{ base $dst }}: |- {{ $.Files.Get $src | nindent 4 }}
{{- end -}}
{{- end -}}
{{- end -}}
45 changes: 21 additions & 24 deletions tools/helm/charts/sparc/templates/_deployment.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,17 @@ spec:
{{- if gt (len .Values.env) 0 }}
checksum/configmap: {{ .Values.env | toYaml | sha256sum }}
{{- end }}
{{- if (.Values.files).files }}
{{- range $file :=.Values.files.files }}
checksum/{{ base $file | replace "." "-" }}: {{ $.Files.Get $file | toYaml | sha256sum }}
{{- if gt (len .Values.files) 0 }}
{{- range $src, $dst :=.Values.files }}
checksum/{{ base $dst | replace "." "-" }}: {{ $.Files.Get $src | toYaml | sha256sum }}
{{- end -}}
{{- end }}
{{- if gt (len .Values.secrets) 0 }}
checksum/secret: {{ .Values.secrets | toYaml | sha256sum }}
{{- end }}
{{- if (.Values.secretFiles).files }}
{{- range $file :=.Values.secretFiles.files }}
checksum/{{ base $file | replace "." "-" }}: {{ $.Files.Get $file | toYaml | sha256sum }}
{{- if gt (len .Values.secretFiles) 0 }}
{{- range $src, $dst :=.Values.secretFiles }}
checksum/{{ base $dst | replace "." "-" }}: {{ $.Files.Get $src | toYaml | sha256sum }}
{{- end -}}
{{- end }}
{{- end }}
Expand Down Expand Up @@ -75,20 +75,22 @@ spec:
{{- end }}
{{- end }}

{{- if (or $.Values.volumes (or ($.Values.files).files ($.Values.secretFiles).files)) }}
{{- if or $.Values.volumeMounts (or $.Values.files $.Values.secretFiles) }}
volumeMounts:
{{- if .Values.volumeMounts }}
{{ .Values.volumeMounts | toYaml | nindent 12 }}
{{- end -}}
{{- if (.Values.files).files }}
{{- range $src, $dst :=.Values.secretFiles }}
- name: {{ $.name}}-secret-files
mountPath: {{ $dst }}
subPath: {{ base $dst }}
{{- end }}
{{- range $src, $dst :=.Values.files }}
- name: {{ $.name}}-files
mountPath: {{ .Values.files.mountPath }}
{{- end -}}
{{- if (.Values.secretFiles).files }}
- name: {{ $.name}}-files-secret
mountPath: {{ .Values.secretFiles.mountPath }}
mountPath: {{ $dst }}
subPath: {{ base $dst }}
{{- end -}}
{{- end }}
{{- end }}

{{- if .Values.port }}
ports:
Expand All @@ -112,23 +114,18 @@ spec:
restartPolicy: Always
terminationGracePeriodSeconds: 30

{{- if (or $.Values.volumes (or ($.Values.files).files ($.Values.secretFiles).files)) }}
{{- if (or $.Values.volumes (or $.Values.files $.Values.secretFiles)) }}
volumes:
{{- if .Values.volumes -}}
{{ tpl (.Values.volumes | toYaml) $ | nindent 8 }}
{{- end -}}
{{- if (.Values.files).files }}
{{- if .Values.files }}
- name: {{ $.name}}-files
configMap:
name: {{ $.name}}-files-configmap
items:
{{- range $key, $value :=.Values.files.files }}
- key: {{ $key }}
path: {{ $key }}
{{- end }}
name: {{ $.name}}-files-configmap
{{- end -}}
{{- if (.Values.secretFiles).files }}
- name: {{ $.name}}-files-secret
{{- if .Values.secretFiles }}
- name: {{ $.name}}-secret-files
secret:
secretName: {{ $.name}}-files-secret
{{- end -}}
Expand Down
Loading

0 comments on commit a626395

Please sign in to comment.