diff --git a/src/DaemonRunner/DaemonRunner/Service/Extensions/HostBuilderExtensions.cs b/src/DaemonRunner/DaemonRunner/Service/Extensions/HostBuilderExtensions.cs new file mode 100644 index 000000000..0f927797d --- /dev/null +++ b/src/DaemonRunner/DaemonRunner/Service/Extensions/HostBuilderExtensions.cs @@ -0,0 +1,30 @@ +using Microsoft.Extensions.Hosting; +using NetDaemon.Service.Support; +using Serilog; + +namespace NetDaemon.Service.Extensions +{ + public static class HostBuilderExtensions + { + // We preserve the static logger so that we can access it statically and early on in the application lifecycle. + private const bool PreserveStaticLogger = true; + + public static IHostBuilder UseNetDaemon(this IHostBuilder builder) + { + return builder + .UseNetDaemonSerilog() + .ConfigureServices(services => + { + services.AddNetDaemon(); + }); + } + + private static IHostBuilder UseNetDaemonSerilog(this IHostBuilder builder) + { + return builder.UseSerilog( + (context, configuration) => SeriLogConfigurator.Configure(configuration), + PreserveStaticLogger + ); + } + } +} \ No newline at end of file diff --git a/src/DaemonRunner/DaemonRunner/Service/Extensions/ServiceCollectionExtensions.cs b/src/DaemonRunner/DaemonRunner/Service/Extensions/ServiceCollectionExtensions.cs new file mode 100644 index 000000000..618bf4aa0 --- /dev/null +++ b/src/DaemonRunner/DaemonRunner/Service/Extensions/ServiceCollectionExtensions.cs @@ -0,0 +1,15 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace NetDaemon.Service.Extensions +{ + public static class ServiceCollectionExtensions + { + public static IServiceCollection AddNetDaemon(this IServiceCollection services) + { + services.AddHttpClient(); + services.AddHostedService(); + + return services; + } + } +} \ No newline at end of file diff --git a/src/DaemonRunner/DaemonRunner/Service/Runner.cs b/src/DaemonRunner/DaemonRunner/Service/Runner.cs new file mode 100644 index 000000000..beb21f37b --- /dev/null +++ b/src/DaemonRunner/DaemonRunner/Service/Runner.cs @@ -0,0 +1,79 @@ +using System; +using System.IO; +using System.Text.Json; +using System.Threading.Tasks; +using Microsoft.Extensions.Hosting; +using NetDaemon.Service.Extensions; +using NetDaemon.Service.Support; +using Serilog; + +namespace NetDaemon.Service +{ + public static class Runner + { + private const string _hassioConfigPath = "/data/options.json"; + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .UseNetDaemon(); + + public static async Task Run(string[] args) + { + try + { + Log.Logger = SeriLogConfigurator.GetConfiguration().CreateLogger(); + + if (File.Exists(_hassioConfigPath)) + { + try + { + var hassAddOnSettings = await JsonSerializer.DeserializeAsync( + File.OpenRead(_hassioConfigPath)).ConfigureAwait(false); + if (hassAddOnSettings.LogLevel is object) + { + SeriLogConfigurator.SetMinimumLogLevel(hassAddOnSettings.LogLevel); + } + if (hassAddOnSettings.GenerateEntitiesOnStart is object) + { + Environment.SetEnvironmentVariable("HASS_GEN_ENTITIES", hassAddOnSettings.GenerateEntitiesOnStart.ToString()); + } + if (hassAddOnSettings.LogMessages is object && hassAddOnSettings.LogMessages == true) + { + Environment.SetEnvironmentVariable("HASSCLIENT_MSGLOGLEVEL", "Default"); + } + if (hassAddOnSettings.ProjectFolder is object && + string.IsNullOrEmpty(hassAddOnSettings.ProjectFolder) == false) + { + Environment.SetEnvironmentVariable("HASS_RUN_PROJECT_FOLDER", hassAddOnSettings.ProjectFolder); + } + + // We are in Hassio so hard code the path + Environment.SetEnvironmentVariable("HASS_DAEMONAPPFOLDER", "/config/netdaemon"); + } + catch (Exception e) + { + Log.Fatal(e, "Failed to read the Home Assistant Add-on config"); + } + } + else + { + var envLogLevel = Environment.GetEnvironmentVariable("HASS_LOG_LEVEL"); + if (!string.IsNullOrEmpty(envLogLevel)) + { + SeriLogConfigurator.SetMinimumLogLevel(envLogLevel); + } + } + + await CreateHostBuilder(args).Build().RunAsync(); + } + catch (Exception e) + { + Log.Fatal(e, "Failed to start host..."); + } + finally + { + Log.CloseAndFlush(); + } + } + } +} \ No newline at end of file diff --git a/src/DaemonRunner/DaemonRunner/Service/RunnerService.cs b/src/DaemonRunner/DaemonRunner/Service/RunnerService.cs index 9ab6e82d2..b18d2a921 100644 --- a/src/DaemonRunner/DaemonRunner/Service/RunnerService.cs +++ b/src/DaemonRunner/DaemonRunner/Service/RunnerService.cs @@ -8,112 +8,14 @@ using System.Threading; using System.Threading.Tasks; using JoySoftware.HomeAssistant.Client; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using NetDaemon.Daemon; using NetDaemon.Daemon.Storage; using NetDaemon.Service.App; -using Serilog; -using Serilog.Core; -using Serilog.Events; -using Serilog.Sinks.SystemConsole.Themes; namespace NetDaemon.Service { - public static class Runner - { - private const string _hassioConfigPath = "/data/options.json"; - private static LoggingLevelSwitch _levelSwitch = new LoggingLevelSwitch(); - - public static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .UseSerilog() - .ConfigureServices(services => - { - services.AddHttpClient(); - services.AddHostedService(); - }); - - public static async Task Run(string[] args) - { - try - { - // Setup serilog - Log.Logger = new LoggerConfiguration() - .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) - .Enrich.FromLogContext() - .MinimumLevel.ControlledBy(_levelSwitch) - .WriteTo.Console(theme: AnsiConsoleTheme.Code) - .CreateLogger(); - - if (File.Exists(_hassioConfigPath)) - { - try - { - var hassAddOnSettings = await JsonSerializer.DeserializeAsync( - File.OpenRead(_hassioConfigPath)).ConfigureAwait(false); - if (hassAddOnSettings.LogLevel is object) - { - _levelSwitch.MinimumLevel = hassAddOnSettings.LogLevel switch - { - "info" => LogEventLevel.Information, - "debug" => LogEventLevel.Debug, - "error" => LogEventLevel.Error, - "warning" => LogEventLevel.Warning, - "trace" => LogEventLevel.Verbose, - _ => LogEventLevel.Information - }; - } - if (hassAddOnSettings.GenerateEntitiesOnStart is object) - { - Environment.SetEnvironmentVariable("HASS_GEN_ENTITIES", hassAddOnSettings.GenerateEntitiesOnStart.ToString()); - } - if (hassAddOnSettings.LogMessages is object && hassAddOnSettings.LogMessages == true) - { - Environment.SetEnvironmentVariable("HASSCLIENT_MSGLOGLEVEL", "Default"); - } - if (hassAddOnSettings.ProjectFolder is object && - string.IsNullOrEmpty(hassAddOnSettings.ProjectFolder) == false) - { - Environment.SetEnvironmentVariable("HASS_RUN_PROJECT_FOLDER", hassAddOnSettings.ProjectFolder); - } - - // We are in Hassio so hard code the path - Environment.SetEnvironmentVariable("HASS_DAEMONAPPFOLDER", "/config/netdaemon"); - } - catch (System.Exception e) - { - Log.Fatal(e, "Failed to read the Home Assistant Add-on config"); - } - } - else - { - var envLogLevel = Environment.GetEnvironmentVariable("HASS_LOG_LEVEL"); - _levelSwitch.MinimumLevel = envLogLevel switch - { - "info" => LogEventLevel.Information, - "debug" => LogEventLevel.Debug, - "error" => LogEventLevel.Error, - "warning" => LogEventLevel.Warning, - "trace" => LogEventLevel.Verbose, - _ => LogEventLevel.Information - }; - } - - CreateHostBuilder(args).Build().Run(); - } - catch (Exception e) - { - Log.Fatal(e, "Failed to start host..."); - } - finally - { - Log.CloseAndFlush(); - } - } - } - public class RunnerService : BackgroundService { /// diff --git a/src/DaemonRunner/DaemonRunner/Service/Support/SeriLogConfigurator.cs b/src/DaemonRunner/DaemonRunner/Service/Support/SeriLogConfigurator.cs new file mode 100644 index 000000000..49035e151 --- /dev/null +++ b/src/DaemonRunner/DaemonRunner/Service/Support/SeriLogConfigurator.cs @@ -0,0 +1,39 @@ +using Serilog; +using Serilog.Core; +using Serilog.Events; +using Serilog.Sinks.SystemConsole.Themes; + +namespace NetDaemon.Service.Support +{ + internal static class SeriLogConfigurator + { + private static readonly LoggingLevelSwitch LevelSwitch = new LoggingLevelSwitch(); + + public static LoggerConfiguration GetConfiguration() + { + return Configure(new LoggerConfiguration()); + } + + public static LoggerConfiguration Configure(LoggerConfiguration configuration) + { + return configuration + .MinimumLevel.ControlledBy(LevelSwitch) + .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) + .Enrich.FromLogContext() + .WriteTo.Console(theme: AnsiConsoleTheme.Code); + } + + public static void SetMinimumLogLevel(string level) + { + LevelSwitch.MinimumLevel = level switch + { + "info" => LogEventLevel.Information, + "debug" => LogEventLevel.Debug, + "error" => LogEventLevel.Error, + "warning" => LogEventLevel.Warning, + "trace" => LogEventLevel.Verbose, + _ => LogEventLevel.Information + }; + } + } +} \ No newline at end of file