c++ logging boost boost-log

c++ - Use la jerarquía de canales de Boost.Log para la gravedad y el filtrado de sumidero



logging boost-log (1)

En Boost.Log los sumideros (los objetos que escriben los archivos de registro) y los registradores (los objetos a través de los cuales su aplicación emite registros de registro) no están conectados directamente, y cualquier receptor puede recibir un mensaje de registro de cualquier registrador. Para que los registros de ciertos registradores aparezcan solo en sumideros particulares, tendrá que organizar los filtros en los sumideros para que los registros innecesarios se supriman para los sumideros que no se supone que los reciban y pasen a otros. Para distinguir los registros de diferentes registradores, los registradores tienen que agregar atributos distintos a cada registro que hacen. Por lo general, esto se logra con los channels : los registradores adjuntarán un atributo de canal que se puede usar para identificar el registrador en los filtros, formateadores o sumideros. Los canales se pueden combined con otros atributos, como los niveles de gravedad. Sin embargo, debe tenerse en cuenta que los canales y los niveles de gravedad son ortogonales, y cualquier canal puede tener registros de cualquier nivel. Los valores de diferentes atributos se analizan por separado en los filtros.

Entonces, por ejemplo, si desea que los registros del canal A se escriban en el archivo A.log, y del canal B - a B.log, debe crear dos sumideros, uno para cada archivo, y configurar sus filtros en consecuencia.

BOOST_LOG_ATTRIBUTE_KEYWORD(a_severity, "Severity", severity_level) BOOST_LOG_ATTRIBUTE_KEYWORD(a_channel, "Channel", std::string) logging::add_file_log( keywords::file_name = "A.log", keywords::filter = a_channel == "A"); logging::add_file_log( keywords::file_name = "B.log", keywords::filter = a_channel == "B");

Consulte los documentos sobre la definición de palabras clave de atributos y funciones de configuración convenientes . Ahora puede crear registradores para cada canal y los registros de registros se enrutarán a los sumideros mediante filtros.

typedef src::severity_channel_logger< severity_level, std::string > logger_type; logger_type lg_a(keywords::channel = "A"); logger_type lg_b(keywords::channel = "B"); BOOST_LOG_SEV(lg_a, info) << "Hello, A.log!"; BOOST_LOG_SEV(lg_b, info) << "Hello, B.log!";

Puede tener tantos registradores para un solo canal como desee: los mensajes de cada uno de ellos se dirigirán a un único sumidero.

Sin embargo, hay dos problemas aquí. Primero, la biblioteca no tiene conocimiento de la naturaleza del canal y lo considera solo un valor opaco. No tiene conocimiento de la jerarquía de canales, por lo que "A" y "A.bb" se consideran canales diferentes y no relacionados. En segundo lugar, configurar filtros como el anterior puede ser difícil si desea que se escriban múltiples canales en un solo archivo (como "A" y "A.bb"). Las cosas se volverán aún más complicadas si desea diferentes niveles de gravedad para diferentes canales.

Si la jerarquía de canales no es crucial para usted, puede facilitar la configuración del filtro con un filtro de umbral de gravedad . Con ese filtro puede establecer un nivel de gravedad mínimo para cada canal correspondiente. Si desea heredar los umbrales de severidad en los subcanales, entonces su única forma es escribir su propio filtro; la biblioteca no proporciona eso fuera de la caja.

Hay varias formas de crear un filtro, pero se reduce a escribir una función que acepte valores de atributo de registros de registros y devuelva true si este registro pasó el filtro y false caso contrario. Quizás, la forma más fácil se muestra en Tutorial , vea el ejemplo con phoenix::bind de Boost.Phoenix .

bool my_filter( logging::value_ref< severity_level, tag::a_severity > const& level, logging::value_ref< std::string, tag::a_channel > const& channel, channel_hierarchy const& thresholds) { // See if the log record has the severity level and the channel attributes if (!level || !channel) return false; std::string const& chan = channel.get(); // Parse the channel string, look for it in the hierarchy // and find out the severity threshold for this channel severity_level threshold = thresholds.find(chan); return level.get() >= threshold; }

Ahora, configurar los sumideros cambiaría así para hacer uso de su nuevo filtro:

logging::add_file_log( keywords::file_name = "A.log", keywords::filter = phoenix::bind(&my_filter, a_severity.or_none(), a_channel.or_none(), hierarchy_A)); logging::add_file_log( keywords::file_name = "B.log", keywords::filter = phoenix::bind(&my_filter, a_severity.or_none(), a_channel.or_none(), hierarchy_B));

Aquí hierarchy_A y hierarchy_B son sus estructuras de datos utilizadas para almacenar umbrales de gravedad para diferentes canales para los dos archivos de registro.

He estado estudiando Boost.Log por un tiempo y creo que ahora es el momento de hacer la transición de mi código base de log4cxx a Boost.Log. Creo que el diseño e implementación de Boost.Log mejorará significativamente el mantenimiento y uso de mi código. Sé que las preguntas frecuentes de Boost.Log tienen una página que dice

En cuanto a los registradores jerárquicos, no hay necesidad de esta característica en el diseño actual de la biblioteca. Uno de los principales beneficios que proporciona en log4j es determinar los anexos (sumideros, en términos de esta biblioteca) en los que terminará un registro de registro. Esta biblioteca logra el mismo resultado al filtrar.

Entiendo la equivalencia conceptual y no estoy tratando de hacer Boost.Log en log4j / log4cxx. Más bien mi pregunta es: ¿Cómo uso Boost.Log para obtener la misma funcionalidad que uso actualmente de log4cxx? En particular, quiero establecer umbrales de gravedad y sumideros para nodos específicos en una fuente de registro o jerarquía de canales. Por ejemplo, tengo fuentes de registro organizadas por libA.moduleB.componentC.logD con niveles en la jerarquía separados por puntos . . Usando log4cxx se puede establecer el umbral general de libA en INFO con el registrador más específico, libA.moduleB , que tiene un umbral de DEPURACIÓN.

libA.threshold=INFO libA.moduleB.threshold=DEBUG

Del mismo modo, uno puede conectar sumideros a nodos arbitrarios en la jerarquía.

Creo que es posible una capacidad similar con Boost.Log, pero necesito ayuda / orientación sobre cómo implementar esto realmente. Además, estoy seguro de que otros que deseen realizar la transición a Boost.Log desde otros marcos tendrán la misma pregunta.

Agradezco sinceramente sus comentarios.