static void Main(string[] args) { Console.WriteLine("Peloton To Garmin"); var config = new Configuration(); Health.Set(HealthStatus.Healthy); var runtimeVersion = Environment.Version.ToString(); var os = Environment.OSVersion.Platform.ToString(); var osVersion = Environment.OSVersion.VersionString; var assembly = Assembly.GetExecutingAssembly(); var versionInfo = FileVersionInfo.GetVersionInfo(assembly.Location); var version = versionInfo.ProductVersion; try { IConfiguration configProviders = new ConfigurationBuilder() .AddJsonFile(Path.Join(Environment.CurrentDirectory, "configuration.local.json"), optional: true, reloadOnChange: true) .AddEnvironmentVariables(prefix: "P2G_") .AddCommandLine(args) .Build(); configProviders.GetSection(nameof(App)).Bind(config.App); configProviders.GetSection(nameof(Format)).Bind(config.Format); configProviders.GetSection(nameof(Peloton)).Bind(config.Peloton); configProviders.GetSection(nameof(Garmin)).Bind(config.Garmin); configProviders.GetSection(nameof(Observability)).Bind(config.Observability); configProviders.GetSection(nameof(Developer)).Bind(config.Developer); // https://github.com/serilog/serilog-settings-configuration Log.Logger = new LoggerConfiguration() .ReadFrom.Configuration(configProviders, sectionName: $"{nameof(Observability)}:Serilog") .Enrich.WithSpan() .CreateLogger(); ChangeToken.OnChange(() => configProviders.GetReloadToken(), () => { Log.Information("Config change detected, reloading config values."); configProviders.GetSection(nameof(App)).Bind(config.App); configProviders.GetSection(nameof(Format)).Bind(config.Format); configProviders.GetSection(nameof(Peloton)).Bind(config.Peloton); configProviders.GetSection(nameof(Garmin)).Bind(config.Garmin); configProviders.GetSection(nameof(Developer)).Bind(config.Developer); GarminUploader.ValidateConfig(config); Log.Information("Config reloaded. Changes will take effect at the end of the current sleeping cycle."); }); Log.Debug("P2G Version: {@Version}", version); Log.Debug("Operating System: {@Os}", osVersion); Log.Debug("DotNet Runtime: {@DotnetRuntime}", runtimeVersion); PelotonService.ValidateConfig(config.Peloton); GarminUploader.ValidateConfig(config); Common.Metrics.ValidateConfig(config.Observability); Tracing.ValidateConfig(config.Observability); FlurlConfiguration.Configure(config); } catch (Exception e) { Log.Fatal(e, "Exception during config setup."); Health.Set(HealthStatus.Dead); throw; } IDisposable dotNetRuntimeMetrics = null; try { using var metrics = Common.Metrics.EnableMetricsServer(config.Observability.Prometheus); using var tracing = Tracing.EnableTracing(config.Observability.Jaeger); using var tracingSource = new ActivitySource("ROOT"); if (config.Observability.Prometheus.Enabled) { dotNetRuntimeMetrics = DotNetRuntimeStatsBuilder .Customize() .WithContentionStats() .WithJitStats() .WithThreadPoolStats() .WithGcStats() .WithExceptionStats() .StartCollecting(); } BuildInfo.WithLabels(version, os, osVersion, runtimeVersion).Set(1); if (config.Peloton.NumWorkoutsToDownload <= 0) { Console.Write("How many workouts to grab? "); int num = Convert.ToInt32(Console.ReadLine()); config.Peloton.NumWorkoutsToDownload = num; } if (config.App.EnablePolling) { while (config.App.EnablePolling) { RunAsync(config).GetAwaiter().GetResult(); Log.Information("Sleeping for {@Seconds} seconds...", config.App.PollingIntervalSeconds); var now = DateTime.UtcNow; var nextRunTime = now.AddSeconds(config.App.PollingIntervalSeconds); NextSyncTime.Set(new DateTimeOffset(nextRunTime).ToUnixTimeSeconds()); Thread.Sleep(config.App.PollingIntervalSeconds * 1000); } } else { RunAsync(config).GetAwaiter().GetResult(); } } catch (Exception e) { Log.Fatal(e, "Uncaught Exception."); Health.Set(HealthStatus.Dead); } finally { Log.CloseAndFlush(); Console.ReadLine(); dotNetRuntimeMetrics?.Dispose(); } }
private async Task RunAsync(CancellationToken cancelToken) { int exitCode = 0; Statics.MetricPrefix = Constants.ConsoleAppName; Statics.TracingService = Constants.ConsoleAppName; using var metrics = Metrics.EnableMetricsServer(_config.Observability.Prometheus); using var metricsCollector = Metrics.EnableCollector(_config.Observability.Prometheus); using var tracing = Tracing.EnableTracing(_config.Observability.Jaeger); using var tracingSource = new ActivitySource("ROOT"); try { if (_settings.Peloton.NumWorkoutsToDownload <= 0) { Console.Write("How many workouts to grab? "); int num = Convert.ToInt32(Console.ReadLine()); _settings.Peloton.NumWorkoutsToDownload = num; } if (_settings.App.EnablePolling) { while (_settings.App.EnablePolling && !cancelToken.IsCancellationRequested) { var syncResult = await _syncService.SyncAsync(_settings.Peloton.NumWorkoutsToDownload); Health.Set(syncResult.SyncSuccess ? HealthStatus.Healthy : HealthStatus.UnHealthy); Log.Information("Sleeping for {@Seconds} seconds...", _settings.App.PollingIntervalSeconds); var now = DateTime.UtcNow; var nextRunTime = now.AddSeconds(_settings.App.PollingIntervalSeconds); NextSyncTime.Set(new DateTimeOffset(nextRunTime).ToUnixTimeSeconds()); Thread.Sleep(_settings.App.PollingIntervalSeconds * 1000); } } else { await _syncService.SyncAsync(_settings.Peloton.NumWorkoutsToDownload); } _logger.Information("Done."); } catch (Exception ex) { _logger.Fatal(ex, "Uncaught Exception"); Health.Set(HealthStatus.Dead); exitCode = -2; } finally { _logger.Verbose("Exit."); if (!_settings.App.CloseWindowOnFinish) { Console.ReadLine(); } Environment.Exit(exitCode); } }