Недавно я использую Serilog в проекте asp.net core 2.1, конфигурация настроена в файле appsettings.json, я хотел бы разделить журналы в разных файлах журналов в соответствии с уровнем журнала, поэтому я попытался выполнить следующее безуспешно:
appsettings.json:
{
"ConnectionStrings": {
"DefaultConnection": "..."
},
"Serilog": {
"MinimumLevel": {
"Default": "Debug",
"Override": {
"Microsoft": "Error",
"System": "Warning"
}
},
"WriteTo": {
"Console-Sink-1": {
"Name": "Console",
"Args": {
"restrictedToMinimumLevel": "Debug",
"outputTemplate": "===> {Timestamp:HH:mm:ss.fff zzz} [{Level}] {Message}{NewLine}{Exception}"
}
},
"File-Sink-1": {
"Name": "RollingFile",
"Args": {
"restrictedToMinimumLevel": "Debug",
"pathFormat": "D:\\SicotX\\Log-debug-{Date}.txt",
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz}|[{Level}]|{Message}{NewLine}{Exception}"
}
},
"File-Sink-2": {
"Name": "RollingFile",
"Args": {
"restrictedToMinimumLevel": "Information",
"pathFormat": "D:\\SicotX\\Log-info-{Date}.txt",
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz}|[{Level}]|{Message}{NewLine}{Exception}"
}
},
"File-Sink-3": {
"Name": "RollingFile",
"Args": {
"restrictedToMinimumLevel": "Error",
"pathFormat": "D:\\SicotX\\Log-error-{Date}.txt",
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz}|[{Level}]|{Message}{NewLine}{Exception}"
}
}
}
},
"AllowedHosts": "*",
"CustomSettings": {
"Cultura": "es-ES",
"ReportServer": "http://192.168.10.169:888"
},
"EmailSettings": {
"Status": "0",
"Host": "smtp.mail.yahoo.com",
"Port": "587",
"User": "myUser",
"Password": "",
"From": "myUser@yahoo.com",
"To": "myUser@yahoo.com",
"CC": ""
}
}
appsettings.Development.json:
{
}
Следующие пакеты nuget, установленные для выполнения serilog:
Конфигурация в program.cs:
public class Program
{
private static string _environmentName;
public static void Main(string[] args)
{
var webHost = CreateWebHost(args);
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{_environmentName}.json", optional: true)
.Build();
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.CreateLogger();
webHost.Run();
}
public static IWebHost CreateWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureLogging((hostingContext, config) =>
{
config.ClearProviders();
_environmentName = hostingContext.HostingEnvironment.EnvironmentName;
})
.UseSetting("https_port", "8080")
.UseStartup<Startup>()
.UseSerilog()
.Build();
}
Startup.cs:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders()
.AddErrorDescriber<IdentityErrorMessageDescriber>();
services.Configure<IdentityOptions>(options =>
{
options.Lockout.AllowedForNewUsers = false;
options.Lockout.MaxFailedAccessAttempts = 5;
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(1440);
options.Password.RequireDigit = true;
options.Password.RequireLowercase = true;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = true;
options.Password.RequiredLength = 8;
options.Password.RequiredUniqueChars = 1;
options.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
});
services.AddAuthentication(); // Como se gestiona a través de Cookies, por defecto (esto se puede cambiar), el nombre del esquema de la cookie es .AspNetCore.Cookies
services.AddAuthorization(options =>
{
options.AddPolicy(nameof(RolePolicy.Administradores),
policy => policy.RequireRole(
nameof(RoleAuthorization.SuperUsuario),
nameof(RoleAuthorization.Administrador)
)
);
});
services.ConfigureApplicationCookie(options =>
{
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(30);
options.LoginPath = new PathString("/Identity/Account/Login");
options.ReturnUrlParameter = CookieAuthenticationDefaults.ReturnUrlParameter;
options.AccessDeniedPath = new PathString("/Identity/Account/AccessDenied");
options.LogoutPath = new PathString("/Identity/Account/Logout");
options.SlidingExpiration = true;
});
// Servicio de Correo Electrónico
services.Configure<EmailOptions>(Configuration.GetSection("EmailSettings"));
// Servicios de Localización y Globalización (Idiomas)
services.Configure<RequestLocalizationOptions>(options =>
{
var supportedCultures = new[]
{
new CultureInfo(Configuration.GetSection("CustomSettings")["Cultura"]),
new CultureInfo("en-US")
};
options.DefaultRequestCulture = new RequestCulture(supportedCultures[0]);
options.SupportedCultures = supportedCultures;
options.SupportedUICultures = supportedCultures;
options.RequestCultureProviders = new List<IRequestCultureProvider>() { new CookieRequestCultureProvider() };
});
services.AddLocalization(options => options.ResourcesPath = "Resources");
services.AddSingleton<MenuLocalizer>();
services.AddSingleton<SharedLocalizer>();
services.AddTransient<IEmailSender, EmaileSender>();
services.AddAutoMapper(options => options.ValidateInlineMaps = false);
services.AddMvc(options =>
{
options.CacheProfiles.Add("DefaultNoCache",
new CacheProfile()
{
Duration = 0,
Location = ResponseCacheLocation.None,
NoStore = true
}
);
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
.AddViewLocalization(options => options.ResourcesPath = "Resources")
.AddDataAnnotationsLocalization()
.AddJsonOptions(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver())
.AddFluentValidation(options => {
options.RegisterValidatorsFromAssemblyContaining<Startup>();
options.RegisterValidatorsFromAssemblyContaining<SharedLocalizer>();
});
services.AddKendo();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory log)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/error/500");
app.UseHsts();
}
app.Use(async (ctx, next) =>
{
await next();
if (ctx.Response.StatusCode == 404 && !ctx.Response.HasStarted)
{
//Re-execute the request so the user gets the error page
string originalPath = ctx.Request.Path.Value;
ctx.Items["originalPath"] = originalPath;
ctx.Request.Path = "/error/404";
await next();
}
});
var locOpt = app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>();
app.UseRequestLocalization(locOpt.Value);
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "areas",
template: "{area:exists}/{controller=Home}/{action=Index}/{id?}"
);
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}"
);
});
}
}
Ошибка: элемент с таким же ключом уже добавлен. Ключ: RollingFile
Трассировка стека:
at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)
at Serilog.Settings.Configuration.ConfigurationReader.GetMethodCalls(IConfigurationSection directive)
at Serilog.Settings.Configuration.ConfigurationReader.ApplySinks(LoggerConfiguration loggerConfiguration, Assembly[] configurationAssemblies)
at Serilog.Configuration.LoggerSettingsConfiguration.Settings(ILoggerSettings settings) in C:\projects\serilog\src\Serilog\Configuration\LoggerSettingsConfiguration.cs:line 44
at SicotX.Program.Main(String[] args) in E:\Projects\Repositories\SicotX\Frontend\SicotX\Program.cs:line 42
Буду признателен за любую подсказку.