/// <summary> /// Construct an <see cref="AdministrationController"/> /// </summary> /// <param name="databaseContext">The <see cref="IDatabaseContext"/> for the <see cref="ApiController"/></param> /// <param name="authenticationContextFactory">The <see cref="IAuthenticationContextFactory"/> for the <see cref="ApiController"/></param> /// <param name="gitHubClientFactory">The value of <see cref="gitHubClientFactory"/></param> /// <param name="serverUpdater">The value of <see cref="serverUpdater"/></param> /// <param name="assemblyInformationProvider">The value of <see cref="assemblyInformationProvider"/></param> /// <param name="ioManager">The value of <see cref="ioManager"/></param> /// <param name="platformIdentifier">The value of <see cref="platformIdentifier"/></param> /// <param name="logger">The <see cref="ILogger"/> for the <see cref="ApiController"/></param> /// <param name="updatesConfigurationOptions">The <see cref="IOptions{TOptions}"/> containing value of <see cref="updatesConfiguration"/></param> /// <param name="generalConfigurationOptions">The <see cref="IOptions{TOptions}"/> containing value of <see cref="generalConfiguration"/></param> /// <param name="fileLoggingConfigurationOptions">The <see cref="IOptions{TOptions}"/> containing value of <see cref="fileLoggingConfiguration"/></param> public AdministrationController( IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, IGitHubClientFactory gitHubClientFactory, IServerControl serverUpdater, IAssemblyInformationProvider assemblyInformationProvider, IIOManager ioManager, IPlatformIdentifier platformIdentifier, ILogger <AdministrationController> logger, IOptions <UpdatesConfiguration> updatesConfigurationOptions, IOptions <GeneralConfiguration> generalConfigurationOptions, IOptions <FileLoggingConfiguration> fileLoggingConfigurationOptions) : base( databaseContext, authenticationContextFactory, logger, false) { this.gitHubClientFactory = gitHubClientFactory ?? throw new ArgumentNullException(nameof(gitHubClientFactory)); this.serverUpdater = serverUpdater ?? throw new ArgumentNullException(nameof(serverUpdater)); this.assemblyInformationProvider = assemblyInformationProvider ?? throw new ArgumentNullException(nameof(assemblyInformationProvider)); this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); this.platformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier)); updatesConfiguration = updatesConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(updatesConfigurationOptions)); generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); fileLoggingConfiguration = fileLoggingConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(fileLoggingConfigurationOptions)); }
public void FileLoggerMinLevelWarn_LogsInfo_FileDoesntExist() { var message = "Some entry"; var config = new FileLoggingConfiguration(); config.MinimumLevel = LogLevel.Warn; Aspects.Logging.ILogger logger = new NLogger(config); logger.Info(message); var fileName = $@"{DateTime.Today.ToString("yyyy-MM-dd")}.log"; var filePath = $@"{Environment.CurrentDirectory}\{fileName}"; Assert.False(File.Exists(filePath)); }
/// <summary> /// Initiate logging in file /// </summary> /// <param name="configuration"></param> /// <param name="levels"></param> public NLogger(FileLoggingConfiguration configuration, params LogLevel[] levels) { LoggingConfiguration = configuration; InitTarget(new FileTarget("file") { CreateDirs = true, ArchiveNumbering = ArchiveNumberingMode.Date, ArchiveEvery = FileArchivePeriod.Day, MaxArchiveFiles = configuration.MaxArchiveFiles, FileName = $"{configuration.LogFileDirectory}/${{shortdate}}.log", ArchiveFileName = $"{configuration.LogFileDirectory}/${{shortdate}}.log", Layout = configuration.MessageTemplate }, levels?.ToList()); }
public void ApplyLoggingConfiguration(bool isUsed, bool isActive, bool wasApplied) { // arrange ApplicationConfigurationHelper.AdjustKeys("log.file", isUsed.ToString()); var serilogConfigurationDummy = new Mock <LoggerConfiguration>(); var sut = new FileLoggingConfiguration(); // act sut.Apply(serilogConfigurationDummy.Object); // assert sut.LogFilePath.Should().Be(FilePath); sut.LogToFile.Should().Be(isUsed); sut.IsActive.Should().Be(isActive); sut.WasApplied.Should().Be(wasApplied); }
public void FileLogger_LogsError_FileExists() { var message = "Some entry"; var config = new FileLoggingConfiguration(); Aspects.Logging.ILogger logger = new NLogger(config); logger.Error(new Exception(message)); var fileName = $@"{DateTime.Today.ToString("yyyy-MM-dd")}.log"; var filePath = $@"{Environment.CurrentDirectory}\{fileName}"; Assert.True(File.Exists(filePath)); var fileText = File.ReadAllText(filePath); Assert.Contains(message, fileText); Assert.Contains("Error", fileText); File.Delete(filePath); }
/// <summary> /// Saves a given <see cref="Configuration"/> set to <paramref name="userConfigFileName"/> /// </summary> /// <param name="userConfigFileName">The file to save the <see cref="Configuration"/> to</param> /// <param name="hostingPort">The hosting port to save</param> /// <param name="databaseConfiguration">The <see cref="DatabaseConfiguration"/> to save</param> /// <param name="newGeneralConfiguration">The <see cref="GeneralConfiguration"/> to save</param> /// <param name="fileLoggingConfiguration">The <see cref="FileLoggingConfiguration"/> to save</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param> /// <returns>A <see cref="Task"/> representing the running operation</returns> async Task SaveConfiguration(string userConfigFileName, ushort?hostingPort, DatabaseConfiguration databaseConfiguration, GeneralConfiguration newGeneralConfiguration, FileLoggingConfiguration fileLoggingConfiguration, CancellationToken cancellationToken) { await console.WriteAsync(String.Format(CultureInfo.InvariantCulture, "Configuration complete! Saving to {0}", userConfigFileName), true, cancellationToken).ConfigureAwait(false); var map = new Dictionary <string, object>() { { DatabaseConfiguration.Section, databaseConfiguration }, { GeneralConfiguration.Section, newGeneralConfiguration }, { FileLoggingConfiguration.Section, fileLoggingConfiguration } }; if (hostingPort.HasValue) { map.Add("Kestrel", new { EndPoints = new { Http = new { Url = String.Format(CultureInfo.InvariantCulture, "http://0.0.0.0:{0}", hostingPort) } } }); } var json = JsonConvert.SerializeObject(map, Formatting.Indented); var configBytes = Encoding.UTF8.GetBytes(json); try { await ioManager.WriteAllBytes(userConfigFileName, configBytes, cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) { throw; } catch (Exception e) { await console.WriteAsync(e.Message, true, cancellationToken).ConfigureAwait(false); await console.WriteAsync(null, true, cancellationToken).ConfigureAwait(false); await console.WriteAsync("For your convienence, here's the json we tried to write out:", true, cancellationToken).ConfigureAwait(false); await console.WriteAsync(null, true, cancellationToken).ConfigureAwait(false); await console.WriteAsync(json, true, cancellationToken).ConfigureAwait(false); await console.WriteAsync(null, true, cancellationToken).ConfigureAwait(false); await console.WriteAsync("Press any key to exit...", true, cancellationToken).ConfigureAwait(false); await console.PressAnyKeyAsync(cancellationToken).ConfigureAwait(false); throw new OperationCanceledException(); } await console.WriteAsync("Waiting for configuration changes to reload...", true, cancellationToken).ConfigureAwait(false); //we need to wait for the configuration's file system watcher to read and reload the changes await Task.Delay(TimeSpan.FromSeconds(5), cancellationToken).ConfigureAwait(false); }
/// <summary> /// Prompts the user to create a <see cref="FileLoggingConfiguration"/> /// </summary> /// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param> /// <returns>A <see cref="Task{TResult}"/> resulting in the new <see cref="FileLoggingConfiguration"/></returns> async Task <FileLoggingConfiguration> ConfigureLogging(CancellationToken cancellationToken) { var fileLoggingConfiguration = new FileLoggingConfiguration(); await console.WriteAsync(null, true, cancellationToken).ConfigureAwait(false); fileLoggingConfiguration.Disable = !await PromptYesNo("Enable file logging? (y/n): ", cancellationToken).ConfigureAwait(false); if (!fileLoggingConfiguration.Disable) { do { await console.WriteAsync("Log file directory path (leave blank for default): ", false, cancellationToken).ConfigureAwait(false); fileLoggingConfiguration.Directory = await console.ReadLineAsync(false, cancellationToken).ConfigureAwait(false); if (String.IsNullOrWhiteSpace(fileLoggingConfiguration.Directory)) { fileLoggingConfiguration.Directory = null; break; } //test a write of it await console.WriteAsync(null, true, cancellationToken).ConfigureAwait(false); await console.WriteAsync("Testing directory access...", true, cancellationToken).ConfigureAwait(false); try { await ioManager.CreateDirectory(fileLoggingConfiguration.Directory, cancellationToken).ConfigureAwait(false); var testFile = ioManager.ConcatPath(fileLoggingConfiguration.Directory, String.Format(CultureInfo.InvariantCulture, "WizardAccesTest.{0}.deleteme", Guid.NewGuid())); await ioManager.WriteAllBytes(testFile, Array.Empty <byte>(), cancellationToken).ConfigureAwait(false); try { await ioManager.DeleteFile(testFile, cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) { throw; } catch (Exception e) { await console.WriteAsync(String.Format(CultureInfo.InvariantCulture, "Error deleting test log file: {0}", testFile), true, cancellationToken).ConfigureAwait(false); await console.WriteAsync(e.Message, true, cancellationToken).ConfigureAwait(false); await console.WriteAsync(null, true, cancellationToken).ConfigureAwait(false); } break; } catch (OperationCanceledException) { throw; } catch (Exception e) { await console.WriteAsync(e.Message, true, cancellationToken).ConfigureAwait(false); await console.WriteAsync(null, true, cancellationToken).ConfigureAwait(false); await console.WriteAsync("Please verify the path is valid and you have access to it!", true, cancellationToken).ConfigureAwait(false); } } while (true); async Task <LogLevel?> PromptLogLevel(string question) { do { await console.WriteAsync(null, true, cancellationToken).ConfigureAwait(false); await console.WriteAsync(question, true, cancellationToken).ConfigureAwait(false); await console.WriteAsync(String.Format(CultureInfo.InvariantCulture, "Enter one of {0}/{1}/{2}/{3}/{4}/{5} (leave blank for default): ", nameof(LogLevel.Trace), nameof(LogLevel.Debug), nameof(LogLevel.Information), nameof(LogLevel.Warning), nameof(LogLevel.Error), nameof(LogLevel.Critical)), false, cancellationToken).ConfigureAwait(false); var responseString = await console.ReadLineAsync(false, cancellationToken).ConfigureAwait(false); if (String.IsNullOrWhiteSpace(responseString)) { return(null); } if (Enum.TryParse <LogLevel>(responseString, out var logLevel) && logLevel != LogLevel.None) { return(logLevel); } await console.WriteAsync("Invalid log level!", true, cancellationToken).ConfigureAwait(false); } while (true); } fileLoggingConfiguration.LogLevel = await PromptLogLevel(String.Format(CultureInfo.InvariantCulture, "Enter the level limit for normal logs (default {0}).", fileLoggingConfiguration.LogLevel)).ConfigureAwait(false) ?? fileLoggingConfiguration.LogLevel; fileLoggingConfiguration.MicrosoftLogLevel = await PromptLogLevel(String.Format(CultureInfo.InvariantCulture, "Enter the level limit for Microsoft logs (VERY verbose, default {0}).", fileLoggingConfiguration.MicrosoftLogLevel)).ConfigureAwait(false) ?? fileLoggingConfiguration.MicrosoftLogLevel; } return(fileLoggingConfiguration); }
/// <summary> /// Saves a given <see cref="Configuration"/> set to <paramref name="userConfigFileName"/> /// </summary> /// <param name="userConfigFileName">The file to save the <see cref="Configuration"/> to</param> /// <param name="hostingPort">The hosting port to save</param> /// <param name="databaseConfiguration">The <see cref="DatabaseConfiguration"/> to save</param> /// <param name="newGeneralConfiguration">The <see cref="GeneralConfiguration"/> to save</param> /// <param name="fileLoggingConfiguration">The <see cref="FileLoggingConfiguration"/> to save</param> /// <param name="controlPanelConfiguration">The <see cref="ControlPanelConfiguration"/> to save</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param> /// <returns>A <see cref="Task"/> representing the running operation</returns> async Task SaveConfiguration(string userConfigFileName, ushort?hostingPort, DatabaseConfiguration databaseConfiguration, GeneralConfiguration newGeneralConfiguration, FileLoggingConfiguration fileLoggingConfiguration, ControlPanelConfiguration controlPanelConfiguration, CancellationToken cancellationToken) { await console.WriteAsync(String.Format(CultureInfo.InvariantCulture, "Configuration complete! Saving to {0}", userConfigFileName), true, cancellationToken).ConfigureAwait(false); newGeneralConfiguration.ApiPort = hostingPort ?? GeneralConfiguration.DefaultApiPort; newGeneralConfiguration.ConfigVersion = GeneralConfiguration.CurrentConfigVersion; var map = new Dictionary <string, object>() { { DatabaseConfiguration.Section, databaseConfiguration }, { GeneralConfiguration.Section, newGeneralConfiguration }, { FileLoggingConfiguration.Section, fileLoggingConfiguration }, { ControlPanelConfiguration.Section, controlPanelConfiguration } }; var json = JsonConvert.SerializeObject(map, Formatting.Indented); var configBytes = Encoding.UTF8.GetBytes(json); try { await ioManager.WriteAllBytes(userConfigFileName, configBytes, cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) { throw; } catch (Exception e) { await console.WriteAsync(e.Message, true, cancellationToken).ConfigureAwait(false); await console.WriteAsync(null, true, cancellationToken).ConfigureAwait(false); await console.WriteAsync("For your convienence, here's the json we tried to write out:", true, cancellationToken).ConfigureAwait(false); await console.WriteAsync(null, true, cancellationToken).ConfigureAwait(false); await console.WriteAsync(json, true, cancellationToken).ConfigureAwait(false); await console.WriteAsync(null, true, cancellationToken).ConfigureAwait(false); await console.WriteAsync("Press any key to exit...", true, cancellationToken).ConfigureAwait(false); await console.PressAnyKeyAsync(cancellationToken).ConfigureAwait(false); throw new OperationCanceledException(); } }
public ILogger Build() { _loggerConfiguration = _loggerConfiguration ?? new LoggerConfiguration(); var jgLoggingConfiguration = new JgLoggingConfiguration(); var enrichLoggingConfig = new EnrichLoggingConfiguration(); _configuration?.Bind("JG-Logging:Enrich", enrichLoggingConfig); _configuration?.Bind("JG-Logging:Serilog", jgLoggingConfiguration); if (jgLoggingConfiguration.WriteToSeq) { var seqLoggingConfig = new SeqLoggingConfiguration(); _configuration?.Bind("JG-Logging:Serilog:Seq", seqLoggingConfig); _loggerConfiguration .Destructure.JsonNetTypes() .WriteTo.Seq( seqLoggingConfig.ServerUrl, seqLoggingConfig.RestrictedToMinimumLevel, seqLoggingConfig.BatchPostingLimit, seqLoggingConfig.Period, seqLoggingConfig.ApiKey, seqLoggingConfig.BufferBaseFilename, seqLoggingConfig.BufferSizeLimitBytes, seqLoggingConfig.EventBodyLimitBytes, seqLoggingConfig.ControlLevelSwitch, null, seqLoggingConfig.RetainedInvalidPayloadsLimitBytes, seqLoggingConfig.Compact, seqLoggingConfig.QueueSizeLimit); } if (jgLoggingConfiguration.WriteToColoredConsole) { _loggerConfiguration.WriteTo.ColoredConsole(); } if (jgLoggingConfiguration.WriteToFile) { var fileLoggingConfig = new FileLoggingConfiguration(); _loggerConfiguration.WriteTo.File( // Note: IIS requires write access Path.Combine(Environment.CurrentDirectory, fileLoggingConfig.Path), fileLoggingConfig.RestrictedToMinimumLevel, fileLoggingConfig.OutputTemplate, null, fileLoggingConfig.FileSizeLimitBytes, fileLoggingConfig.LevelSwitch, fileLoggingConfig.Buffered, fileLoggingConfig.Shared, fileLoggingConfig.FlushToDiskInterval, fileLoggingConfig.RollingInterval, fileLoggingConfig.RollOnFileSizeLimit, fileLoggingConfig.RetainedFileCountLimit); } _loggerConfiguration .Enrich.FromLogContext() .Enrich.WithExceptionDetails() .Enrich.WithMachineName() .Enrich.WithEnvironmentUserName() .Enrich.WithProcessName() .Enrich.WithProcessId() .Enrich.WithProperty(LogProps.APPLICATION, "JG.FinTechTest") .Enrich.WithProperty(LogProps.ENVIRONMENT, _environment) .Enrich.WithProperty(LogProps.ENV_NAME, enrichLoggingConfig.EnvName); _loggerConfiguration.MinimumLevel.Debug() .MinimumLevel.Override("Microsoft", LogEventLevel.Error) .MinimumLevel.Override("System", LogEventLevel.Error); _loggerConfiguration.Enrich.With(new CorrelationEnricher(new CorrelationContextAccessor())); // TODO: Revisit this, although Props is shorter, how much does it cost us to clone the dictionary? _loggerConfiguration.Destructure.ByTransformingWhere <Props>(type => type == typeof(Props), value => value.ToDictionary(entry => entry.Key, entry => entry.Value)); return(_loggerConfiguration.CreateLogger()); }