Implementing an orthogonal log level that gets dumped into a socket

流过昼夜 提交于 2020-01-02 13:34:19

问题


I'm using boost log and want to implement an extra log level that is independent of the existing log levels.

This log level will be activated on-demand, if there is a listening client connected to the daemons socket (independent of the current configured log level).

Is this possible to implement?

I suspect that the on-demand functionality can be implemented through a custom sink that will either discard, or send the data. But how do I integrate this with the rest of the logging code?


回答1:


Let's separate the goals you want to achieve. If I understand correctly:

  1. You want some log records to be sent through a socket to another process.
  2. Only select log records need to be sent, others need not.
  3. You want to enable or disable this functionality at run time.

Each of these points can be achieved by extending or customizing different parts of Boost.Log. Let's see how each of these goals can be achieved.

1. Create a custom sink backend.

Boost.Log uses sinks to process log records. It does not provide a sink for sending records over a socket, so you are correct in that you will need to write one. There is a tutorial on this. Note that you only need to write a backend, i.e. the part that actually sends the records. The part that implements thread synchronization and filtering is already provided by the library in the form of several frontends, which you can use with your custom backend.

The important decision here is the format in which you want to send log records over the network. The easiest to implement is the text-based format because you can use formatters provided by the library to compose the string from the log record. If you need a binary format then you will have to implement serialization yourself (perhaps, with help of Boost.Serialization or another library). What you most likely will have to do is extract attribute values from the log record views in order to serialize them into the binary form suitable for sending. We'll get back to attributes in a moment.

When your sink backend is implemented, you can select a suitable frontend and add your sink to the logging core. This can be done once at your application startup, and it can be done even if at that point log records do not need to be sent.

2. Mark log records with attributes.

Any kind of data you want to put to log is represented with attributes. This includes timestamps, severity levels and even the log message itself. Log records are basically collections of values generated by those attributes, with associated attribute names. If you want to differentiate some log records from others (in your case to selectively send them through your sink) you have to mark them with a distinct attribute. Severity levels don't suit well for this because, as you said, you want to send records regardless of their level.

You can use channels as the means to route some of the log records to your new sink. A channel is another attribute (typically, a string) which can be analyzed by filters in order to block log records for some sinks and pass to others. Channels, severity levels and for that matter any other attributes can be used together to form log records that you pass to the library. For example, here is a commonly used logger that supports both channels and severity levels.

There are other ways to mark your log records. For example, you can use scoped attributes to mark log records made in a particular scope with an attribute. The advantage of this approach is that this way you can mark any log records made through any logger, without even having to access that logger.

3. Configure filters.

As I already mentioned, in order to select which log records make it to your sink you will have to set a filter to your sink. Filters are managed by sink frontends, so you don't have to implement it in your backend. The filter will check the attribute values for every log record your application emits and only pass those records which satisfy the condition. For example, you can set a filter that will only pass records with a specific value of the channel attribute attached. Or you can set a filter that will always return false, effectively disabling logging through your sink. You can set filters at any time, so you can modify logging behavior on request. You only need to keep the pointer to your sink available somewhere to be able to set filters to it when needed.



来源:https://stackoverflow.com/questions/31429825/implementing-an-orthogonal-log-level-that-gets-dumped-into-a-socket

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!