Skip to content

Commit

Permalink
[gh-1150] Update feature metrics to use dimensions
Browse files Browse the repository at this point in the history
  • Loading branch information
ashmind committed Jan 6, 2024
1 parent b521cbe commit 572d95d
Show file tree
Hide file tree
Showing 37 changed files with 651 additions and 747 deletions.
54 changes: 27 additions & 27 deletions source/Container.Manager/Azure/ContainerCountMetricReporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,39 +8,39 @@
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace SharpLab.Container.Manager.Azure {
public class ContainerCountMetricReporter : BackgroundService {
private static readonly string ContainerProcessName = Path.GetFileNameWithoutExtension(Container.Program.ExeFileName);
private static readonly MetricIdentifier ContainerCountMetric = new("Custom Metrics", "Container Count");
namespace SharpLab.Container.Manager.Azure;

private readonly TelemetryClient _telemetryClient;
private readonly ILogger<ContainerCountMetricReporter> _logger;
public class ContainerCountMetricReporter : BackgroundService {
private static readonly string ContainerProcessName = Path.GetFileNameWithoutExtension(Container.Program.ExeFileName);
private static readonly MetricIdentifier ContainerCountMetric = new("Custom Metrics", "Container Count");

public ContainerCountMetricReporter(
TelemetryClient telemetryClient,
ILogger<ContainerCountMetricReporter> logger
) {
_telemetryClient = telemetryClient;
_logger = logger;
}
private readonly TelemetryClient _telemetryClient;
private readonly ILogger<ContainerCountMetricReporter> _logger;

protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
while (!stoppingToken.IsCancellationRequested) {
try {
var count = 0;
foreach (var process in Process.GetProcessesByName(ContainerProcessName)) {
count += 1;
process.Dispose();
}
public ContainerCountMetricReporter(
TelemetryClient telemetryClient,
ILogger<ContainerCountMetricReporter> logger
) {
_telemetryClient = telemetryClient;
_logger = logger;
}

_telemetryClient.GetMetric(ContainerCountMetric).TrackValue(count);
}
catch (Exception ex) {
_logger.LogError(ex, "Failed to report container count");
await Task.Delay(TimeSpan.FromMinutes(4), stoppingToken);
protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
while (!stoppingToken.IsCancellationRequested) {
try {
var count = 0;
foreach (var process in Process.GetProcessesByName(ContainerProcessName)) {
count += 1;
process.Dispose();
}
await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);

_telemetryClient.GetMetric(ContainerCountMetric).TrackValue(count);
}
catch (Exception ex) {
_logger.LogError(ex, "Failed to report container count");
await Task.Delay(TimeSpan.FromMinutes(4), stoppingToken);
}
await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
}
}
}
100 changes: 50 additions & 50 deletions source/Container.Manager/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,67 +9,67 @@
using SharpLab.Container.Manager.Endpoints;
using SharpLab.Container.Manager.Internal;

namespace SharpLab.Container.Manager {
[SupportedOSPlatform("windows")]
public class Startup {
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
namespace SharpLab.Container.Manager;

public void ConfigureServices(IServiceCollection services)
{
// TODO: proper DI, e.g. Autofac
services.AddSingleton(new ProcessRunnerConfiguration(
workingDirectoryPath: AppContext.BaseDirectory,
exeFileName: Container.Program.ExeFileName,
essentialAccessCapabilitySid: "S-1-15-3-1024-4233803318-1181731508-1220533431-3050556506-2713139869-1168708946-594703785-1824610955",
maximumMemorySize: 30 * 1024 * 1024,
maximumCpuPercentage: 1
));
services.AddSingleton<IProcessRunner, ProcessRunner>();
services.AddSingleton<IDateTimeProvider, DateTimeProvider>();
[SupportedOSPlatform("windows")]
public class Startup {
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940

services.AddSingleton<StatusEndpoint>();
public void ConfigureServices(IServiceCollection services)
{
// TODO: proper DI, e.g. Autofac
services.AddSingleton(new ProcessRunnerConfiguration(
workingDirectoryPath: AppContext.BaseDirectory,
exeFileName: Container.Program.ExeFileName,
essentialAccessCapabilitySid: "S-1-15-3-1024-4233803318-1181731508-1220533431-3050556506-2713139869-1168708946-594703785-1824610955",
maximumMemorySize: 30 * 1024 * 1024,
maximumCpuPercentage: 1
));
services.AddSingleton<IProcessRunner, ProcessRunner>();
services.AddSingleton<IDateTimeProvider, DateTimeProvider>();

var authorizationToken = Environment.GetEnvironmentVariable("SHARPLAB_CONTAINER_HOST_AUTHORIZATION_TOKEN")
?? throw new Exception("Required environment variable SHARPLAB_CONTAINER_HOST_AUTHORIZATION_TOKEN was not provided.");
services.AddSingleton(new ExecutionEndpointSettings(authorizationToken));
services.AddSingleton<ExecutionEndpoint>();
services.AddSingleton<StatusEndpoint>();

services.AddSingleton<ContainerPool>();
var authorizationToken = Environment.GetEnvironmentVariable("SHARPLAB_CONTAINER_HOST_AUTHORIZATION_TOKEN")
?? throw new Exception("Required environment variable SHARPLAB_CONTAINER_HOST_AUTHORIZATION_TOKEN was not provided.");
services.AddSingleton(new ExecutionEndpointSettings(authorizationToken));
services.AddSingleton<ExecutionEndpoint>();

services.AddHostedService<ContainerAllocationWorker>();
services.AddSingleton<ContainerCleanupWorker>();
services.AddHostedService(c => c.GetRequiredService<ContainerCleanupWorker>());
services.AddSingleton<ContainerPool>();

services.AddSingleton<StdinWriter>();
services.AddSingleton<StdoutReader>();
services.AddSingleton<ExecutionProcessor>();
services.AddSingleton<CrashSuspensionManager>();
services.AddSingleton<ExecutionManager>();
services.AddHostedService<ContainerAllocationWorker>();
services.AddSingleton<ContainerCleanupWorker>();
services.AddHostedService(c => c.GetRequiredService<ContainerCleanupWorker>());

ConfigureAzureDependentServices(services);
}
services.AddSingleton<StdinWriter>();
services.AddSingleton<StdoutReader>();
services.AddSingleton<ExecutionProcessor>();
services.AddSingleton<CrashSuspensionManager>();
services.AddSingleton<ExecutionManager>();

private void ConfigureAzureDependentServices(IServiceCollection services) {
var connectionString = Environment.GetEnvironmentVariable("SHARPLAB_TELEMETRY_CONNECTION_STRING");
if (connectionString == null) {
Console.WriteLine("[WARN] AppInsights connection string was not found.");
return;
}
ConfigureAzureDependentServices(services);
}

var configuration = new TelemetryConfiguration { ConnectionString = connectionString };
services.AddSingleton(new TelemetryClient(configuration));
services.AddHostedService<ContainerCountMetricReporter>();
private void ConfigureAzureDependentServices(IServiceCollection services) {
var connectionString = Environment.GetEnvironmentVariable("SHARPLAB_TELEMETRY_CONNECTION_STRING");
if (connectionString == null) {
Console.WriteLine("[WARN] AppInsights connection string was not found.");
return;
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app) {
app.UseRouting();
var configuration = new TelemetryConfiguration { ConnectionString = connectionString };
services.AddSingleton(new TelemetryClient(configuration));
services.AddHostedService<ContainerCountMetricReporter>();
}

app.UseEndpoints(endpoints => {
endpoints.MapGet("/status", app.ApplicationServices.GetRequiredService<StatusEndpoint>().ExecuteAsync);
endpoints.MapPost("/", app.ApplicationServices.GetRequiredService<ExecutionEndpoint>().ExecuteAsync);
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app) {
app.UseRouting();

app.UseEndpoints(endpoints => {
endpoints.MapGet("/status", app.ApplicationServices.GetRequiredService<StatusEndpoint>().ExecuteAsync);
endpoints.MapPost("/", app.ApplicationServices.GetRequiredService<ExecutionEndpoint>().ExecuteAsync);
});
}
}
102 changes: 51 additions & 51 deletions source/NetFramework/Server/Common/CommonModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,56 +7,56 @@
using SharpLab.Server.Common.Internal;
using SharpLab.Server.Common.Languages;

namespace SharpLab.Server.Common {
[UsedImplicitly]
public class CommonModule : Module {
protected override void Load(ContainerBuilder builder) {
RegisterExternals(builder);

builder.RegisterType<AssemblyReferenceCollector>()
.As<IAssemblyReferenceCollector>()
.SingleInstance();

builder.RegisterType<PreCachedAssemblyResolver>()
.As<ICSharpCode.Decompiler.Metadata.IAssemblyResolver>()
.As<Mono.Cecil.IAssemblyResolver>()
.SingleInstance();

builder.RegisterType<CSharpAdapter>()
.As<ILanguageAdapter>()
.SingleInstance();

builder.RegisterType<VisualBasicAdapter>()
.As<ILanguageAdapter>()
.SingleInstance();

builder.RegisterType<FSharpAdapter>()
.As<ILanguageAdapter>()
.SingleInstance();

builder.RegisterType<ILAdapter>()
.As<ILanguageAdapter>()
.SingleInstance();

var webAppName = EnvironmentHelper.GetRequiredEnvironmentVariable("SHARPLAB_WEBAPP_NAME");
builder.RegisterType<FeatureTracker>()
.As<IFeatureTracker>()
.SingleInstance()
.WithParameter("webAppName", webAppName);
}

private void RegisterExternals(ContainerBuilder builder) {
builder.RegisterInstance(new RecyclableMemoryStreamManager())
.AsSelf();

builder.RegisterInstance<Func<HttpClient>>(() => new HttpClient())
.As<Func<HttpClient>>()
.SingleInstance()
.PreserveExistingDefaults(); // allows tests and other overrides

builder.RegisterType<PortablePdbReaderProvider>()
.As<ISymbolReaderProvider>()
.SingleInstance();
}
namespace SharpLab.Server.Common;

[UsedImplicitly]
public class CommonModule : Module {
protected override void Load(ContainerBuilder builder) {
RegisterExternals(builder);

builder.RegisterType<AssemblyReferenceCollector>()
.As<IAssemblyReferenceCollector>()
.SingleInstance();

builder.RegisterType<PreCachedAssemblyResolver>()
.As<ICSharpCode.Decompiler.Metadata.IAssemblyResolver>()
.As<Mono.Cecil.IAssemblyResolver>()
.SingleInstance();

builder.RegisterType<CSharpAdapter>()
.As<ILanguageAdapter>()
.SingleInstance();

builder.RegisterType<VisualBasicAdapter>()
.As<ILanguageAdapter>()
.SingleInstance();

builder.RegisterType<FSharpAdapter>()
.As<ILanguageAdapter>()
.SingleInstance();

builder.RegisterType<ILAdapter>()
.As<ILanguageAdapter>()
.SingleInstance();

var webAppName = EnvironmentHelper.GetRequiredEnvironmentVariable("SHARPLAB_WEBAPP_NAME");
builder.RegisterType<FeatureTracker>()
.As<IFeatureTracker>()
.SingleInstance()
.WithParameter("webAppName", webAppName);
}

private void RegisterExternals(ContainerBuilder builder) {
builder.RegisterInstance(new RecyclableMemoryStreamManager())
.AsSelf();

builder.RegisterInstance<Func<HttpClient>>(() => new HttpClient())
.As<Func<HttpClient>>()
.SingleInstance()
.PreserveExistingDefaults(); // allows tests and other overrides

builder.RegisterType<PortablePdbReaderProvider>()
.As<ISymbolReaderProvider>()
.SingleInstance();
}
}
46 changes: 15 additions & 31 deletions source/NetFramework/Server/Common/FeatureTracker.cs
Original file line number Diff line number Diff line change
@@ -1,51 +1,35 @@
using SharpLab.Server.Monitoring;
using System.Collections.Generic;
using System.Linq;

namespace SharpLab.Server.Common;

public class FeatureTracker : IFeatureTracker {
private readonly IMetricMonitor _branchMonitor;
private readonly IReadOnlyDictionary<string, IMetricMonitor> _languageMetricMonitors;
private readonly IReadOnlyDictionary<string, IMetricMonitor> _targetMetricMonitors;
private readonly IMetricMonitor _optimizeDebugMonitor;
private readonly IMetricMonitor _optimizeReleaseMonitor;
private readonly string _webAppName;
private readonly IOneDimensionMetricMonitor _branchMetricMonitor;
private readonly IOneDimensionMetricMonitor _languageMetricMonitor;
private readonly IOneDimensionMetricMonitor _targetMetricMonitor;
private readonly IOneDimensionMetricMonitor _optimizeMetricMonitor;

public FeatureTracker(IMonitor monitor, string webAppName) {
_branchMonitor = monitor.MetricSlow("feature", $"Branch: {webAppName}");
_languageMetricMonitors = LanguageNames.All.ToDictionary(
name => name,
name => monitor.MetricSlow("feature", $"Language: {name}")
);
_targetMetricMonitors = TargetNames.All.ToDictionary(
name => name,
name => monitor.MetricSlow("feature", $"Target: {name}")
);

_optimizeDebugMonitor = monitor.MetricSlow("feature", "Optimize: Debug");
_optimizeReleaseMonitor = monitor.MetricSlow("feature", "Optimize: Release");
_webAppName = webAppName;
_branchMetricMonitor = monitor.MetricSlow("feature", "Branch", "Branch");
_languageMetricMonitor = monitor.MetricSlow("feature", "Language", "Language");
_targetMetricMonitor = monitor.MetricSlow("feature", "Target", "Target");
_optimizeMetricMonitor = monitor.MetricSlow("feature", "Optimize", "Optimize");
}

public void TrackBranch() {
_branchMonitor.Track(1);
_branchMetricMonitor.Track(_webAppName, 1);
}

public void TrackLanguage(string languageName) {
if (_languageMetricMonitors.TryGetValue(languageName, out var metricMonitor))
metricMonitor.Track(1);
_languageMetricMonitor.Track(languageName, 1);
}

public void TrackTarget(string targetName) {
if (_targetMetricMonitors.TryGetValue(targetName, out var metricMonitor))
metricMonitor.Track(1);
_targetMetricMonitor.Track(targetName, 1);
}

public void TrackOptimize(string? optimize) {
var monitor = optimize switch {
Optimize.Debug => _optimizeDebugMonitor,
Optimize.Release => _optimizeReleaseMonitor,
_ => null
};
monitor?.Track(1);
public void TrackOptimize(string optimize) {
_optimizeMetricMonitor.Track(optimize, 1);
}
}
2 changes: 1 addition & 1 deletion source/NetFramework/Server/Common/IFeatureTracker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ public interface IFeatureTracker {
void TrackBranch();
void TrackLanguage(string languageName);
void TrackTarget(string targetName);
void TrackOptimize(string? optimize);
void TrackOptimize(string optimize);
}
5 changes: 0 additions & 5 deletions source/NetFramework/Server/Common/LanguageNames.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System.Collections.Immutable;
using CodeAnalysis = Microsoft.CodeAnalysis;

namespace SharpLab.Server.Common;
Expand All @@ -8,8 +7,4 @@ public class LanguageNames {
public const string VisualBasic = CodeAnalysis.LanguageNames.VisualBasic;
public const string FSharp = CodeAnalysis.LanguageNames.FSharp;
public const string IL = "IL";

public static readonly ImmutableArray<string> All = ImmutableArray.Create(
CSharp, VisualBasic, FSharp, IL
);
}
6 changes: 0 additions & 6 deletions source/NetFramework/Server/Common/TargetNames.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using System.Collections.Immutable;

namespace SharpLab.Server.Common;

public static class TargetNames {
Expand All @@ -10,8 +8,4 @@ public static class TargetNames {
public const string Run = "Run";
public const string Verify = "Verify";
public const string Explain = "Explain";

public static readonly ImmutableArray<string> All = ImmutableArray.Create(
CSharp, IL, Ast, JitAsm, Run, Verify, Explain
);
}
Loading

0 comments on commit 572d95d

Please sign in to comment.