diff --git a/src/Exceptionless.Core/Bootstrapper.cs b/src/Exceptionless.Core/Bootstrapper.cs index 4003f53ceb..ed0ece67e8 100644 --- a/src/Exceptionless.Core/Bootstrapper.cs +++ b/src/Exceptionless.Core/Bootstrapper.cs @@ -26,6 +26,7 @@ using Exceptionless.Serializer; using FluentValidation; using Foundatio.Caching; +using Foundatio.Extensions.Hosting.Cronos; using Foundatio.Extensions.Hosting.Jobs; using Foundatio.Extensions.Hosting.Startup; using Foundatio.Jobs; @@ -252,22 +253,22 @@ private static async Task CreateSampleDataAsync(IServiceProvider container) public static void AddHostedJobs(IServiceCollection services, ILoggerFactory loggerFactory) { - services.AddJob(o => o.WaitForStartupActions(true)); - services.AddJob(o => o.WaitForStartupActions(true)); - services.AddJob(o => o.WaitForStartupActions(true)); - services.AddJob(o => o.WaitForStartupActions(true)); - services.AddJob(o => o.WaitForStartupActions(true)); - services.AddJob(o => o.WaitForStartupActions(true)); - services.AddJob(o => o.WaitForStartupActions(true)); - services.AddJob(o => o.WaitForStartupActions(true)); - services.AddJob(o => o.WaitForStartupActions(true)); - services.AddJob(o => o.WaitForStartupActions(true)); - services.AddJob(o => o.WaitForStartupActions(true)); - - services.AddCronJob("30 */4 * * *"); - services.AddCronJob("45 */8 * * *"); - services.AddCronJob("0 1 * * *"); - services.AddCronJob("10 */2 * * *"); + services.AddJob(o => o.WaitForStartupActions()); + services.AddJob(o => o.WaitForStartupActions()); + services.AddJob(o => o.WaitForStartupActions()); + services.AddJob(o => o.WaitForStartupActions()); + services.AddJob(o => o.WaitForStartupActions()); + services.AddJob(o => o.WaitForStartupActions()); + services.AddJob(o => o.WaitForStartupActions()); + services.AddJob(o => o.WaitForStartupActions()); + services.AddJob(o => o.WaitForStartupActions()); + services.AddJob(o => o.WaitForStartupActions()); + + services.AddDistributedCronJob(Cron.Minutely()); + services.AddDistributedCronJob("30 */4 * * *"); + services.AddDistributedCronJob("45 */8 * * *"); + services.AddDistributedCronJob(Cron.Daily(1)); + services.AddDistributedCronJob("10 */2 * * *"); var logger = loggerFactory.CreateLogger(); logger.LogWarning("Jobs running in process"); diff --git a/src/Exceptionless.Core/Services/UsageService.cs b/src/Exceptionless.Core/Services/UsageService.cs index 6a42e10823..fb7cb4436d 100644 --- a/src/Exceptionless.Core/Services/UsageService.cs +++ b/src/Exceptionless.Core/Services/UsageService.cs @@ -50,6 +50,8 @@ private async Task SavePendingOrganizationUsageAsync(DateTime utcNow) if (lastUsageSaveCache.HasValue) lastUsageSave = lastUsageSaveCache.Value.Add(_bucketSize); + _logger.LogInformation("Saving organization usage starting from: {LastUsageSave}...", lastUsageSave); + var bucketUtc = lastUsageSave; var currentBucketUtc = utcNow.Floor(_bucketSize); @@ -127,6 +129,8 @@ private async Task SavePendingProjectUsageAsync(DateTime utcNow) if (lastUsageSaveCache.HasValue) lastUsageSave = lastUsageSaveCache.Value.Add(_bucketSize); + _logger.LogInformation("Saving project usage starting from: {LastUsageSave}...", lastUsageSave); + var bucketUtc = lastUsageSave; var currentBucketUtc = utcNow.Floor(_bucketSize); diff --git a/src/Exceptionless.Web/ApmExtensions.cs b/src/Exceptionless.Web/ApmExtensions.cs index 5712bd8d25..c9d8f1bfbf 100644 --- a/src/Exceptionless.Web/ApmExtensions.cs +++ b/src/Exceptionless.Web/ApmExtensions.cs @@ -84,10 +84,7 @@ public static IHostBuilder AddApm(this IHostBuilder builder, ApmConfig config) b.AddConsoleExporter(); if (config.EnableExporter) - b.AddFilteredOtlpExporter(c => - { - c.Filter = a => a.Duration > TimeSpan.FromMilliseconds(config.MinDurationMs) || a.GetTagItem("db.system") is not null; - }); + b.AddOtlpExporter(); }); services.AddOpenTelemetry().WithMetrics(b => @@ -177,84 +174,3 @@ public ApmConfig(IConfigurationRoot config, string processName, string? serviceV public bool Debug => _apmConfig.GetValue("Debug", false); public bool Console => _apmConfig.GetValue("Console", false); } - -public sealed class CustomFilterProcessor : CompositeProcessor -{ - private readonly Func? _filter; - - public CustomFilterProcessor(BaseProcessor processor, Func? filter) : base(new[] { processor }) - { - _filter = filter; - } - - public override void OnEnd(Activity activity) - { - if (_filter is null || _filter(activity)) - base.OnEnd(activity); - } -} - -public static class CustomFilterProcessorExtensions -{ - public static TracerProviderBuilder AddFilteredOtlpExporter(this TracerProviderBuilder builder, Action? configure = null) - { - ArgumentNullException.ThrowIfNull(builder); - - if (builder is IDeferredTracerProviderBuilder deferredTracerProviderBuilder) - { - return deferredTracerProviderBuilder.Configure((sp, providerBuilder) => - { - var oltpOptions = sp.GetService>()?.Value ?? new FilteredOtlpExporterOptions(); - AddFilteredOtlpExporter(providerBuilder, oltpOptions, configure, sp); - }); - } - - return AddFilteredOtlpExporter(builder, new FilteredOtlpExporterOptions(), configure, serviceProvider: null); - } - - internal static TracerProviderBuilder AddFilteredOtlpExporter( - TracerProviderBuilder builder, - FilteredOtlpExporterOptions exporterOptions, - Action? configure, - IServiceProvider? serviceProvider, - Func, BaseExporter>? configureExporterInstance = null) - { - - configure?.Invoke(exporterOptions); - - exporterOptions.TryEnableIHttpClientFactoryIntegration(serviceProvider, "OtlpTraceExporter"); - - BaseExporter otlpExporter = new OtlpTraceExporter(exporterOptions); - - if (configureExporterInstance is not null) - otlpExporter = configureExporterInstance(otlpExporter); - - if (exporterOptions.ExportProcessorType == ExportProcessorType.Simple) - { - return builder.AddProcessor(new CustomFilterProcessor(new SimpleActivityExportProcessor(otlpExporter), exporterOptions.Filter)); - } - - var batchOptions = exporterOptions.BatchExportProcessorOptions ?? new(); - return builder.AddProcessor(new CustomFilterProcessor(new BatchActivityExportProcessor( - otlpExporter, - batchOptions.MaxQueueSize, - batchOptions.ScheduledDelayMilliseconds, - batchOptions.ExporterTimeoutMilliseconds, - batchOptions.MaxExportBatchSize), exporterOptions.Filter)); - } - - public static void TryEnableIHttpClientFactoryIntegration(this OtlpExporterOptions options, IServiceProvider? serviceProvider, string httpClientName) - { - // use reflection to call the method - var exporterExtensionsType = typeof(OtlpExporterOptions).Assembly.GetType("OpenTelemetry.Exporter.OtlpExporterOptionsExtensions"); - exporterExtensionsType?.GetMethod("TryEnableIHttpClientFactoryIntegration")?.Invoke(null, [options, - serviceProvider!, - httpClientName - ]); - } -} - -public class FilteredOtlpExporterOptions : OtlpExporterOptions -{ - public Func? Filter { get; set; } -}