spdlog custom log tags - c++

I would like to add some extra data to my log output depending on where it was logged. For instance I might have System A and System B, both spitting out log data, but perhaps I'm only interested in System B's log lines now so I could filter based on the tag.
In a previous system I had a log function that looked like LOG(level, tag, message) but I could also see a solution that could involve instantiating a logger with a tag for each system that would pipe to a default logger that catches all messages. So spdlog::tagged_logger systemALogger("System A");
This is almost the answer since loggers can have names, I could use the names as a tag, but can loggers redirect to a default logger? The default logger has several sinks that I would have to attach to the named logging solution.
So the final question would be, is there a way to add a custom tag to log messages in spdlog?

Once you have your log configured, you can clone() it and pass a custom logger name that will appear in the log output (given you have not change the formatting).
auto logger = spdlog::default_logger()->clone("my_logger");
logger->info("message from custom logger");
spdlog::info("message from default logger");
The contents of the basic-log.txt is as follows:
[2020-12-02 09:35:58.801] [my_logger] [info] message from custom logger
[2020-12-02 09:35:58.802] [info] message from default logger

Related

Temporary disable console output for boost::log

I added sink to file via boost::log::add_file_log and console output via boost::log::add_console_log. I am calling a logger via BOOST_LOG_SEV and everything workds perfectely. But there is a place, where a want output only to the file.
How I can disable cosole output in certain place?
You could achieve this with attributes and filters. For example, you could set up a filter in your console sink to suppress any log records that have (or don't have, depending on your preference) a particular attribute value attached.
boost::log::add_console_log
(
...
boost::log::keywords::filter = !boost::log::expressions::has_attr("NoConsole")
...
);
Then you could set this attribute in the code region that shouldn't output logs in the console. For example, you could use a scoped attribute:
BOOST_LOG_SCOPED_THREAD_ATTR("NoConsole", true);
BOOST_LOG(logger) << "No console output";
You can use whatever method of setting the attribute - as a thread-local attribute, or a logger-specific, it doesn't matter.
The important difference from temporarily removing the sink is that the solution with attributes will not affect other threads that may be logging while you're suspending console output.
You can easely do it with remove_sink() function.
console_sink = boost::log::add_console_log(std::cout);
boost::log::core::get()->remove_sink(console_sink);
After that you can call an add_console_log() again and enable console output.

Python logging adds additional handlers

I'm trying to get to grips with Python's logging module which frankly so far has not been approachable. Currently I have one 'main' logger in my main script:
logger = logging.getLogger(__name__)
handler = logging.FileHandler('debug.log')
handler.setFormatter(logging.Formatter('%(levelname)s: %(asctime)s: %(name)s: %(message)s'))
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)
logger.debug(
'{} run for {} using {} values.'.format(
skill, str(datetime.now()), key, mode
)
)
and I have a secondary logger in an imported module:
logger = logging.getLogger(__name__)
handler = logging.FileHandler('debug.log')
handler.setFormatter(logging.Formatter('%(levelname)s: %(asctime)s: %(name)s: %(message)s'))
logger.addHandler(handler)
However, although I tell both loggers to log to a file only (both only have the handlers I've set), I still get information printed to stout from the root logger. Calling logging.root.handlers shows the logger has a StreamHandler which only appears when importing the module containing the second module.
My hacking method of solving the additional stream is to just delete from the roots handlers. However, this feels like a non-canonical solution. I'm assuming I've implemented the module wrong in some way rather than this being the intended function of the module. How are you meant to set up loggers in this hierarchical fashion correctly?
A proper [mcve] would certainly help here - I can't reproduce this root logger handler suddenly appearing out of the blue.
This being said, you're doing it wrong anyway: one of the main goals of the logging module and which is not clearly, explicitely documented is to separate logger's usage (.getLogger() and logger.log()) calls from logging configuration.
The point is that library code cannot know in which context it will be used - only the application will -, so library code should NOT try to configure their loggers in anyway - just get a logger and use it, period. Then it's up to the application (here your main.py script) to configure the loggers for the libs (hint: the .dictConfig() function is by far the most usable way to configure eveything at once).

My Logger object is sending two messages instead of one

I'm trying to create a Logger object which can log info to my console without having the root name.
# Set up logger.
logger = logging.getLogger()
handler = logging.StreamHandler()
handler.setLevel(logging.DEBUG)
handler.setFormatter(logging.Formatter("%(levelname)s:%(message)s"))
logger.addHandler(handler)
logger.info("test")
Returns two logging messages: the correct one set up by handler and the original if i hadn't added a handler, what's the issue?
INFO:root:test
INFO:test
After messing around with it, I'm finding that this only occurs if a) I am adding the handler or b) I import another module with a logger.
I thought you've missed
logger.setLevel(logging.DEBUG)
before doing logging, you just set for your handler
without this, I could not get any output
and since you got two output, maybe you got other files that also create an logger ?

apple logger (ASL) ignoring rule in /etc/asl.conf for specific facility

I've got a C/C++/Objective-C project that send asl logging messages.
The default configuration in asl.conf route all log message with level above notice to system log (see below rule), and I'd like to cancel this rule for my specific facility only.
This means, that all log messages under my facility will be routed to my log file only, and not to system.log.
here's the configuraiton where my facility is defined to com.bla.bla
asl.conf
? [<= Level notice] file system.log
my_asl.conf
? [<= Level notice] [=Facility com.bla.bla] skip / ignore
I've tried both skip and ignore, but i didn't made any change. the only thing that work is to erase the rule from asl.conf, but i don't want to change the behavior of other processes / facilities and to modify some default rules.
is there any rule i can add to ban my messages only from system.log ?
thanks
After re-reading asl.conf man page over and over again, I've found out that i can use 'claim' command to ignore asl.conf base configuration file for my specific rule
claim Messages that match the query associated with a 'claim' action are not processed by the main ASL configuration file /etc/asl.conf. While claimed messages are not pro-cessed processed cessed by /etc/asl.conf, they are not completely private. Other modules may also claim messages, and in some cases two or more modules may have claim actions that match the same messages. This action only blocks processing by /etc/asl.conf.
The `claim' action may be followed by the keyword 'only'. In this case, only those messages that match the 'claim only' query will be processed by subsequent
rules in the module.
I followed the description of the tag 'claim' and added the following configuration to my config file :
? [= com.bla.bla] file /var/log/my-log
? [= com.bla.bla] claim

How can I force Log4net from failing silently so that I might implement the FailoverAppender?

Log4j has an appender called the FailoverAppender. This appender allows you to choose a primary appender and as many secondary appenders as you'd like. If the primary appender fails to log, the secondary kicks in and logs. I noticed that Log4Net does not have this type of appender. I know that Log4Net can log in parallel, but I'd much rather have a secondary appender activated and log only if the primary appender fails. What's preventing me from accomplishing this is that Log4Net is a fail-stop logging system. Is there a way to force an exception to be thrown from an appender when logging fails so that I can implement a FailoverAppender? I'm thinking I need to override some public ErrorHandler which implements IErrorHandler. I've been trying to tailor the ForwardingAppender to do what I want, but since each attached appender fails silently, I can't get things to work. Any and all help would be greatly appreciated. If there are examples out there, please point me to them.
So, after reading stuartd's answer, I did a bit more research on implementing IErrorHandler. During that research, I stumbled across the FallbackAppender. I feel a bit foolish now that I've found this. I just thought I'd put this answer out there so others can find the FallbackAppender a lot quicker. Thanks peer and stuartd. I appreciate the responses.
You can write your own custom failover appender from a SkeletonAppender. If logging fails, remove your current appender and add your backup appender like:
class FailoverAppender : AppenderSkeleton {
protected override void Append(LoggingEvent loggingEvent) {
try {
//Add the appender implementation
}
catch (Exception e) {
try{
//Remove the current appender and add an other, then append the message to the new appender
var root = ((log4net.Repository.Hierarchy.Hierarchy)LogManager.GetRepository()).Root;
var attachable = root as IAppenderAttachable;
attachable.RemoveAppender(this);
AppenderOnError appender = new AppenderOnError(); //Your backup appender
attachable.AddAppender(appender);
appender.Append(loggingEvent);
}
catch (Exception e2){
ErrorHandler.Error("An error occurred while connecting to the logging service.", e);
}
}
}
}
There's an example from the log4net mailing list of how to implement IErrorHandler:
log4net uses a plugin framework for error handling, each Appender has
an ErrorHandler property which holds an IErrorHandler object. This is
used to handle errors reported by the Appender. The default error
handler used is the OnlyOnceErrorHandler and this writes the first
error only (per appender) to the console.
If you want to handle errors in a custom way all you need to do is to
create your own implementation of the IErrorHandler interface and then
set the ErrorHandler property on the appenders to use this new type,
for example:
<appender ...>
...
<errorHandler type="MyErrorHandler, MyAssembly"/>
</appender>
Error handlers can only be set on appenders and there is no way of
globally overriding the default error handler for all appenders.
Your error handler then can perform the failover logging.