I defined a Logger this way with LogLevel FATAL for Console log:
LoggerConfiguration logCfg = new LoggerConfiguration();
logCfg
.MinimumLevel.Debug()
.MinimumLevel.Override("Microsoft", LogEventLevel.Error)
.Enrich.FromLogContext()
.Enrich.With(new UtcTimestampEnricher())
.Enrich.WithProperty("SENDER", applicationName)
//ToDo, extend the Logger for DB to log an active GUID
//.Enrich.WithProperty("GUID", guid)
.WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Fatal)
.WriteTo.File(applicationLogPath,
restrictedToMinimumLevel: logEventLvlFile,
outputTemplate: fileOutputTemplate,
rollOnFileSizeLimit: changeOnFileSizeLimit,
fileSizeLimitBytes: fileSize,
retainedFileCountLimit: retainedFileCount);
But this will be displayed on Console:
_logger.LogInformation("Worker pulling config at: {time}", DateTimeOffset.Now);
This was the solution:
foreach (ServiceDescriptor serviceDescriptor in logging.Services)
{
if (serviceDescriptor.ImplementationType == typeof(Microsoft.Extensions.Logging.Console.ConsoleLoggerProvider))
{
// remove ConsoleLoggerProvider service only
logging.Services.Remove(serviceDescriptor);
break;
}
}
logging.AddSerilog();
Related
I want to create a seperate log file for each HTTP request made to the application. When ever a request is made to the application, it has to generate a log file in the following format
debug20220713.log
debug20220713_001.log
debug20220713_002.log
Here in each log file there should be only one log available.
Log.Logger = new LoggerConfiguration()
.Enrich.WithExceptionDetails()
.Enrich.FromLogContext()
.WriteTo.Async(y =>
y.Logger(m =>
{
m.WriteTo.File(
new ExpressionTemplate(jsonErrorTemplate),
"error.log", LogEventLevel.Warning,
rollingInterval: RollingInterval.Day);
m.Filter.ByIncludingOnly(e => e.Level == LogEventLevel.Warning || e.Level == LogEventLevel.Error);
})
)
.WriteTo.Async(x =>
x.Logger(l =>
{
l.WriteTo.File(new ExpressionTemplate(jsonLogTemplate),
"debug.log", LogEventLevel.Information,
rollingInterval: RollingInterval.Day);
l.Filter.ByIncludingOnly(e => e.Level == LogEventLevel.Information);
}))
.CreateLogger();
I ended up creating own verision of RollingFileSink which matches my requirement. but internally I still use FileSink class. When I call constructor of FileSink I get this error
"This type and constructor will be removed from the public API in a future version; use WriteTo.File() instead."
So I have a simple method to make logger instances for me.
It is as follows
protected ILogger GetIndividualLogger(ILogger parentLogger, LogEventLevel minimumLevel, string RootDir, string Type, string Name, bool shouldBuffer, bool shouldBeShared, TimeSpan flushToDiskInterval)
{
var LogAllFile = $"{RootDir}{Path.DirectorySeparatorChar}{Name}{Path.DirectorySeparatorChar}RAL-{Type}-{Name}-.log";
var LogWarningFile = $"{RootDir}{Path.DirectorySeparatorChar}{Name}{Path.DirectorySeparatorChar}Warnings{Path.DirectorySeparatorChar}RAL-{Type}-{Name}-.log";
ILogger logger = new LoggerConfiguration()
.MinimumLevel.Is(minimumLevel)
.Enrich.WithDemystifiedStackTraces()
.WriteTo.Async(a => a.Logger(parentLogger))
.WriteTo.Async(a => a.File(LogAllFile, outputTemplate: SerilogHereHelper.TemplateForHere, rollingInterval: RollingInterval.Day, buffered: shouldBuffer, shared: shouldBeShared))
.WriteTo.Async(a => a.File(LogWarningFile, restrictedToMinimumLevel: LogEventLevel.Warning, outputTemplate: SerilogHereHelper.TemplateForHere, rollingInterval: RollingInterval.Day, buffered: shouldBuffer, shared: shouldBeShared, flushToDiskInterval: flushToDiskInterval))
.CreateLogger();
return logger;
}
Here is an example call to GetIndividualLogger
GetIndividualLogger(parentLogger: mainLogger, minimumLevel: LogEventLevel.Information, RootDir: _stackLightLogPath, Type: "Stack Light", Name: "Stack Light 1", shouldBuffer: true, shouldBeShared: false, flushToDiskInterval: TimeSpan.FromSecond(2))
The warning level sink will write, but then the other sink, which is usually set to debug or information will create an empty file but never add any entries to it.
I would expect both files to have all warning level entries or above.
I would expect the "LogAllFile" to have all entries at or above the minimum level, but it is blank.
Is there something wrong with my logger config? or is my problem elsewhere?
So the answer to the problem was silly. The warning log was being flushed to disk every 2 seconds, but the main log file was not so all I needed to do was to just pass a value in for flushToDiskInterval
.WriteTo.Async(a => a.File(LogAllFile, outputTemplate: SerilogHereHelper.TemplateForHere, rollingInterval: RollingInterval.Day, buffered: shouldBuffer, shared: shouldBeShared, flushToDiskInterval: flushToDiskInterval))
I have following log4j configuration:
log4j = {
appenders {
appender new DailyRollingFileAppender(name: 'dailyAppender', ...)
}
root {
error 'dailyAppender'
}
info 'dailyAppender' : 'com.intelli', 'grails.app'
}
the "grails.app" logger is for grails artefacts (service, controllers, ..), while the "com.intelli" is for other custom loggers (like /src/groovy/**, ...) initialized with LogFactory class.
Now the issue is, that with this configuration the custom loggers ('com.intelli') were not logging anything. However grails controllers and services were logging fine!
When I changed the order of loggers:
log4j = {
...
info 'dailyAppender' : 'grails.app', 'com.intelli'
}
The custom loggers were logging fine, however grails services and controllers were not logging at all!
The solution is very tricky, you need to enclose the loggers in list ("[ ]") brackets:
log4j = {
appenders {
appender new DailyRollingFileAppender(name: 'dailyAppender', ...)
}
root {
error 'dailyAppender', additivity: false
}
info 'dailyAppender' : ['com.intelli', 'grails.app']
}
With this config, everything logs as it should.
This is not part of the issue, but to prevent double logging, we need to set additivity to false:
log4j = {
appenders {
appender new DailyRollingFileAppender(name: 'dailyAppender', ...)
}
root {
error 'dailyAppender'
}
info 'dailyAppender' : ['com.intelli', 'grails.app'], additivity: false
}
I am trying to debug a simple problem with saving my domain object.
class AppRideOfferController {
def index() {}
def create() {
if(params.fromAddr && params.toAddr && params.preferences && params.startDate) {
RideOffer rideOffer = new RideOffer(startLocation: params.fromAddr, endLocation: params.toAddr, startDateTime: new Date(Integer.parseInt((String) params.startDate)));
rideOffer.save(flush: true);
//assert(rideOffer.id);
log.info("blah");
render(contentType:"text/json") {
result(blah: rideOffer)
};
}
}
}
In the above code, I am simply creating a domain object, saving it, and returning it as json with the generated id in it. However, if I uncomment the asset statement, it fails because id is not set.
I do not get any error on the console, so I wonder how do I get runtime error stacktraces onto the stdout? My Config.groovy's log4j configuration looks like this:
log4j = {
// Example of changing the log pattern for the default console appender:
//
appenders {
console name:'stdout', layout:pattern(conversionPattern: '%c{2} %m%n')
}
info 'grails.app.controllers',
'grails.app.controller',
'grails.app';
error 'org.codehaus.groovy.grails.web.servlet', // controllers
'org.codehaus.groovy.grails.web.pages', // GSP
'org.codehaus.groovy.grails.web.sitemesh', // layouts
'org.codehaus.groovy.grails.web.mapping.filter', // URL mapping
'org.codehaus.groovy.grails.web.mapping', // URL mapping
'org.codehaus.groovy.grails.commons', // core / classloading
'org.codehaus.groovy.grails.plugins', // plugins
'org.codehaus.groovy.grails.orm.hibernate', // hibernate integration
'org.springframework',
'org.hibernate',
'net.sf.ehcache.hibernate'
}
If your code generates a runtime error, you will see the error.gsp view. In the documentation you can see that the save() will not produce an exception, but populate errors that can happen in the validation of your domain class. If you generate your controller you will see how you can handle errors in the save method.
Something like:
def save() {
if(!instance.save(flush:true)) {
//instance fails in validation, you need to respond those errors
Locale locale = RequestContextUtils.getLocale(request) //Locale of the user
render([success: false, errors: errorsToMap(instance.errors, locale)]) as JSON
} else {
render([success: true, record: instance]) as JSON
}
}
//just a helper to format the errors output
private List<Map> errorsToMap(Errors errors, Locale locale) {
def error = []
for(def err : errors.allErrors) {
if(err instanceof FieldError) {
error << [id: err.field, msg: Holders.grailsApplication.mainContext.getMessage(err, locale)]
}
}
return error
}
Holders, JSON and RequestContextUtils are available by default.
Try replacing rideOffer.save(flush: true); with rideOffer.save(flush: true, failOnError:true); and you should see errors in console
My Grails application is going to mirgate an existing database to a new database. I got some unformatted email addresses from the existing database which do not pass validation with my Grails application because of a constraint (email:true), so I get a field error.
I want write these field errors in a log file. How can I do that? I tried a Appender in log4J. It will somehow create a log file so-call "migration.log", but it does not write any field error into this log file.
log4j = {
// Example of changing the log pattern for the default console
// appender:
//
appenders {
// console name:'stdout', layout:pattern(conversionPattern: '%c{2} %m%n')
appender new FileAppender(
name: "migrationAppender",file : "migration.log", layout: pattern(conversionPattern: "%c{2} %m%n")
)
}
This is configration. I define a FileAppender.
In my service. I just call the following:
def foundation = new Foundation(name: name, foundationName: foundationName).addToAddresses(address).addToCommunicationMedia(email)
foundation.validate()
if (!foundation.hasErrors()) {
foundation.save(flush: true)
}
else {
log.error "${foundation.errors}"
}
In the console, the errors occur and I saw a "migration.log" has been created, but somehow the file in empty.
Error 2011-09-26 09:00:29,543 [main] ERROR service.MasterDataMigrationService - org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'de.rvgmbh.nemesis.migration.domain.partner.participant.IndividualPerson' on field 'communicationMedia[0].address': rejected value [erbelrechtsanwalt-eberl.de];
log4j = {
appenders {
rollingFile name:"file", maxFileSize:(1024*1024), file:"migration.log", maxBackupIndex:10
environments {
development {
console name:'stdout'
}
}
}
error 'org.codehaus.groovy.grails.web.servlet', // controllers
'org.codehaus.groovy.grails.web.pages', // GSP
'org.codehaus.groovy.grails.web.sitemesh', // layouts
'org.codehaus.groovy.grails.web.mapping.filter', // URL mapping
'org.codehaus.groovy.grails.web.mapping', // URL mapping
'org.codehaus.groovy.grails.commons', // core / classloading
'org.codehaus.groovy.grails.plugins', // plugins
'org.codehaus.groovy.grails.orm.hibernate', // hibernate integration
'org.springframework',
'org.hibernate',
'net.sf.ehcache.hibernate'
warn 'org.mortbay.log'
environments {
development {
root {
info 'file', 'stdout'
}
debug 'grails.app'
}//development
test {
root {
info 'file'
}
info 'grails.app'
}
production {
root {
info 'file'
}
info 'grails.app'
}
}
}
dev: logs to console and file from debug level
test: logs to file from info level
prod: logs to file from info level