Estoy escribiendo una biblioteca que tiene mucha información que puede ser útil en un registro en el programa que la usa, pero no sé la mejor manera de exponerla de tal manera que el programa que usa mi biblioteca pueda integrar los registros de mi biblioteca con sus propios registros aparentemente (si lo desea).
Elegir una biblioteca de registro específica para mi biblioteca se agrega a la lista de dependencias para usar mi biblioteca y vincula el programa principal a esa biblioteca, y si varias bibliotecas utilizadas por el programa principal hicieran esto, cada una podría haber seleccionado una biblioteca diferente .
Pensé en hacer que el programa registre un objeto de flujo de C ++ con la biblioteca para que lo use. Parece que sería un propósito relativamente general, pero también pensé en que el programa principal registrara una función de devolución de llamada que se solicitaría con los contenidos y metadatos cuando se registran los datos. Otra opción sería almacenar los datos de registro en la biblioteca en algún tipo de lista para que el programa principal los tome cuando quiera tratar con esos datos, dejando que el programa principal decida cuándo tiene tiempo para manejar los datos.
Estoy buscando sugerencias y pros / contras de diferentes enfoques para poder decidir qué es lo mejor en mi situación.
Respuestas:
Puede exponer varios métodos para recibir el registro desde su biblioteca y envolver todos los adaptadores menos uno en el "real" utilizado en la biblioteca.
Por ejemplo, decide tener internamente una
std::function<void(std::string)>
colección que es cada devolución de llamada del registrador. Tu provees:y también
y también
y más variaciones de los tipos de "recibir cadenas de algún lugar" para las que desea implementar adaptadores.
fuente
La forma más sencilla de permitir que una aplicación pueda acceder a la funcionalidad de registro es permitirle registrar una clase / función para recibir el mensaje de registro. Lo que hacen con ese mensaje depende totalmente de la aplicación.
Con C / C ++, puede usar lo siguiente en su biblioteca:
Una aplicación puede registrar una función llamando
registerLogMessageReceiver
. con lo apropiadouser_data
. En la sección de registro de su base de código, debe asegurarse de llamar a esa función con el mensaje apropiado y el registradouser_data
.Si no tiene que preocuparse por C, puede usar una clase como receptor de mensajes.
y agregue una función en la biblioteca para permitir que una aplicación registre un receptor de mensajes de registro.
Una aplicación puede registrar un
LogMessageReceiver
llamando a la función anterior. Deberá tomar algunas decisiones de política con respecto a la propiedad de los registradosLogMessageReceiver
. Si la biblioteca toma posesión del receptor, debe serdelete
el puntero. Si la biblioteca no toma posesión del receptor, la aplicación debe cuidardelete
el receptor.El uso de una clase como el receptor de mensajes de registro permite
user_data
que se omita el bitregisterLogMessageReceiver
ya que el subtipo deLogMessageReceiver
es libre de contener cualquier dato que sea útil para su funcionamiento. No necesita pasar ningún dato de usuario adicional en lareceive
función.A partir de ahí, puede volverse más complejo dependiendo de cuán sofisticado sea su mecanismo de registro.
Por ejemplo, podría tener varios niveles de registro: Conciso, Normal, Detallado o LoggingLevel1, LoggingLevel2, ..., LoggingLevelN.
En ese caso, deberá permitir que la aplicación controle el nivel de registro que desea utilizar.
Hay un conjunto interminable de opciones una vez que decide ir más allá del mecanismo de registro simplista. No tiene sentido profundizar en ellos aquí.
fuente
Yo afirmaría que debería repensar la necesidad de tener un registro junto con su biblioteca; Especialmente para C ++ donde no hay una interfaz de registrador estándar.
Las diferentes aplicaciones tienen diferentes políticas con respecto al registro. Una biblioteca debe ser independiente de las políticas.
El propósito de una biblioteca es proporcionar un servicio y, preferiblemente, indicar si una solicitud de ese servicio tuvo éxito o no; idealmente con una indicación de por qué [falló] a través de errno, código de retorno, excepción ... Si su deseo de iniciar sesión se debe a que una función proporcionada puede fallar en varios lugares, podría estar intentando hacer demasiado en una función. Quizás no , pero considere la posibilidad.
fuente
[...] answer can be “don’t do that" [...]
.Escribir una biblioteca que interactúe fácilmente con el sistema de registro de la aplicación host es fácil, siempre que sepa qué es ese sistema. Cuando hay múltiples posibilidades para eso, es más difícil y estás limitado por la tiranía del mínimo común denominador. Podría tener una capa de compatibilidad que adapte su biblioteca a los diversos sistemas de registro, pero ahora no puede confiar en alguna característica útil y única que solo tiene un sistema. Si el usuario final tiene el otro sistema, esa útil característica única no está allí.
En el mundo .Net, hay (al menos) dos sistemas de registro de uso común, log4net y NLog. Ambos son similares, pero no idénticos. Ya estaba usando log4net, y luego comencé a usar NHibernate (una biblioteca ORM). Afortunadamente, utiliza log4net internamente, por lo que fue fácil agregarlo a un proyecto. (Y aquí no estoy de acuerdo con la respuesta de @Daniel: a veces es tremendamente útil para NHibernate registrar su actividad con gran detalle en el mismo sistema que estoy usando en otro lugar, sin trabajo adicional). Si ya estaba invertido en NLog, eso significa que Me cambio, o tengo un proyecto que usa ambos.
Al menos con el registro, generalmente existe la opción de crear un anexo de mensaje personalizado que puede configurar para reenviar un mensaje registrado en un sistema al otro sistema de registro. Entonces, si ya estaba usando NLog y realmente quería continuar con él, pero también usaba NHibernate, podría apretar los dientes y escribir un apéndice log4net que reenvíe cada mensaje a NLog. Sería sencillo hacerlo si las API son similares.
Las alternativas son realmente elegir el mejor sistema para sus necesidades que esté disponible y usarlo sin reservas, o tener algún tipo de capa adaptadora, que esté sujeta al problema del mínimo común denominador. Lo cual no es una respuesta muy satisfactoria.
fuente