2010-09-29 21 views
40

Hay un montón de diferentes bibliotecas de registro para elegir, cada una con sus propios caprichos y ventajas. (Ejemplos de .NET: log4net, System.Diagnostics.TraceSource, nLog, etc.)¿Cuál es el punto de una fachada de explotación maderera?

La inclinación natural es abstraer esas peculiaridades y utilizar una fachada de registro. (Ejemplos: Castle.Services.Logging, Common.Logging, Simple Logging Facade) De esta manera, si un marco de trabajo de registro determinado que está utilizando se queda obsoleto, o uno diferente entra en boga, puede simplemente cambiar la implementación y dejar el código intacto.

Pero hay múltiples fachadas de registro para elegir. Dado que la respuesta a muchas implementaciones de registro dispares fue la abstracción, ¿por qué no utilizar una fachada de fachada de registro? Si eso suena ridículo, ¿qué lo hace más ridículo que la fachada de tala original? ¿Qué hace que una capa extra de abstracción sobre el marco de registro sea el número mágico?

+9

http://www.joelonsoftware.com/articles/fog0000000018.html –

+0

@brian No estoy seguro de que su suposición sobre la inclinación natural de las personas sea cierta. Insista en que la mayoría de los desarrolladores ni siquiera lo piensan. – Howiecamp

Respuesta

58

Hablaré principalmente desde la perspectiva del uso de la abstracción para aislar el código de la aplicación de un marco de registro particular. Hay otros factores que pueden afectar la elección de un marco de trabajo de registro o la elección de uno (y los requisitos para) una abstracción.

He pasado mucho tiempo evaluando recientemente diversos marcos de trabajo de registro, así como abstracciones de registro de terceros.

Algunas personas sienten que es útil aislar su código de aplicación de un marco de registro específico. Encontrará muchas publicaciones aquí en SO como this y this y this (y hay más) donde se discute el registro y muchas personas lo toman como una cuestión de que el marco de registro debe ser envuelto/abstraído.

Obviamente, esto le permite no estar atado a un marco específico. ¿Es esto importante? ¿Realmente cambiarás tu marco de trabajo? Bueno, también hay muchas personas que no mencionan envolver o que recomiendan no hacerlo. Si nos fijamos en algunos de los ejemplos del código de envoltura del marco de registro que se ha publicado aquí, también puede ver muchos ejemplos de por qué algunas personas no deberían envolver su marco de registro.

Si ha iniciado un proyecto recientemente, es posible que haya examinado los marcos de registro y, tal vez, lo haya reducido a dos finalistas: log4net y NLog. Cada uno tiene argumentos a su favor. log4net es claramente un favorito, probablemente EL favorito de aquellos que han expresado una opinión. NLog proporciona capacidades muy similares. A juzgar por la popularidad, log4net podría ser la opción más clara. Según las capacidades, parecen muy similares. En función de la "actividad reciente" (como lo indican los registros de sus repositorios de código fuente por actividad del blog o la falta de ellos), NLog será la opción más clara. Si tuvo que elegir hace un año, puede ir con log4net ya que sería la opción "segura". No estaba claro cuándo se lanzaría NLog. En el año transcurrido desde entonces, NLog ha pasado por un ciclo de desarrollo bastante significativo, lanzando una versión beta hace unos días.

¿Qué elegir hace un año? ¿Qué elegir ahora? ¿Fue una opción claramente mejor entonces? ¿Una es la mejor opción ahora?

Una cosa que una abstracción le proporciona es la capacidad de posponer la decisión de cuál elegir (ni siquiera necesariamente TIENE que elegir SIEMPRE, aunque es probable que desee hacerlo si planea entregar el marco de trabajo de registro con su producto). Puede probar una unidad y luego la otra y obtener una idea de cómo funcionan con su aplicación, con su equipo, en su entorno. Usar algo como Common.Logging o SLF le permite comenzar a escribir código ahora, codificando a alguna interfaz/API de registro y obteniendo su código de registro en su lugar. Si cree que la interfaz/API es provista por la abstracción es suficiente para su trabajo (y, por qué no sería, ya que es esencialmente lo mismo que la interfaz/API proporcionada por log4net y NLog), entonces no hay mucho peligro al usar la abstracción. A medida que avanza en el ciclo de desarrollo, puede encontrar que un marco u otro se adapta mejor a sus necesidades. Después de haber codificado la abstracción, puede elegir libremente en cualquier momento, hasta que su producto salga por la puerta.

Incluso podría pensar, en el fondo de su mente, que posiblemente podría escribir una biblioteca de registro desde cero. Nuevamente, si usted cree que la interfaz/API de log4net y/o NLog es suficiente, puede implementar su biblioteca de registro con una API similar. Si crees eso, esa podría ser otra razón para usar una abstracción. De nuevo, puede comenzar a escribir código (para su producto, no su biblioteca de registro) hoy, iniciando sesión con algún otro marco de registro hasta el momento en que su biblioteca de registro "desde cero" esté lista. Quizás desee utilizar System.Diagnostics.TraceSource y Ukadc.Diagnostics (para obtener capacidades de formato de salida similares a log4net o NLog) para que pueda obtener una "mejor" integración con el registro que Microsoft ha implementado en algunas de sus plataformas utilizando TraceSources. Podría ser muy fácil escribir un "registrador" en términos de TraceSources y luego escribir la abstracción para que pueda conectarlo a Common.Logging o SLF. (Si la interfaz/API es suficiente, puede simplemente escribir su "registrador" en términos de la interfaz de la biblioteca de abstracción y no tener que escribir una capa de abstracción adicional).

Con argumentos tan persuasivos como estos, ¿por qué alguien nunca usaría una abstracción? ¡Jaja solo bromeo!

Si una abstracción es buena, ¿debería escribir una propia o usar una ya existente? Si escribes uno por tu cuenta, obviamente tienes que escribirlo. ¿Cómo hace uno esto? Bueno, puedes definir una interfaz y ajustar un marco (¡ten cuidado y envuélvelo correctamente!). Más tarde, si decides que quieres cambiar, ajusta ese marco.Si tiene cuidado, no tiene que cambiar ningún código de aplicación, excepto tal vez el lugar donde realmente crea los objetos del marco subyacente. Quizás esto es bueno. Ha evitado una dependencia en la abstracción de un tercero por el precio "pequeño" de implementar un único contenedor en un marco único. Sin embargo, hay un costo. Hasta que haya escrito su abstracción, no podrá escribir mucho código de aplicación que tenga un inicio de sesión, a menos que tenga una buena estrategia para cambiarlo a su abstracción. También se vuelve más difícil probar dos o más marcos para decidir cuál funciona mejor para usted. Cada marco que desee "probar" requiere otro trabajo de ajuste. Si desea cambiar entre frameworks fácilmente (al menos durante el ciclo de desarrollo), tiene trabajo que hacer para hacerlo más fácil. Los marcos de terceros proporcionan esto fuera de la caja.

¡Guau! ¡Ahora estoy vendido! Dame la extracción de registros, o dame la muerte!

¿Las abstracciones de la extracción de registros son todas gravy? ¿Hay algún inconveniente? No pueden ESO genial, ¿verdad?

Bueno, como siempre, cuando "compras" algo o cuando obtienes algo gratis, obtienes lo que está disponible. Las abstracciones de extracción no son diferentes. Ni Common.Logging ni SLF exponen al menos un conjunto muy importante de capacidades de log4net/NLog - las capacidades de contexto de registro (GDC, MDC, NDC). Estos pueden ser clave para obtener la información adecuada registrada y formateada para que pueda obtener el máximo valor de su. SLF no proporciona una abstracción de TraceSource. Tampoco proporciona funciones habilitadas para IsXXX. Common.Logging proporciona una abstracción de TraceSource. Castle.Logging DOES expone GDC/MDC/NDC para log4net y NLog. También proporciona una abstracción de TraceSource. La abstracción TraceSource de Castle también mejora el registro de TraceSource al proporcionar una capacidad de nomenclatura "jerárquica", similar a la proporcionada por log4net y NLog. ¡Se ve muy bien!

Además, estos proyectos son todos de código abierto de una forma u otra. Entonces, dependiendo de la abstracción, los desarrolladores podrían tener más o menos un interés personal en mantenerlo actualizado y agregar nuevas características. Common.Logging ha pasado por algunas versiones y se utiliza, AFAIK, en Spring.Net. Parece razonablemente activo, al menos históricamente. Castle.Logging se usa en el marco Castle. Por lo tanto, aparentemente tienen clientes "reales" y están obteniendo un uso del "mundo real", lo que con suerte conducirá a más implementación de funciones. SLF, por lo que puedo decir, no se usa como parte de una plataforma de desarrollo "real", por lo que es difícil decir cuánto se ejerce.

No está claro cuál es la hoja de ruta para estas plataformas. Common.Logging tiene algunas características próximas enumeradas en su sitio web, pero no indica claramente cuándo estarán disponibles. El sitio web dice "junio", pero ¿de qué año? ¿Con qué frecuencia se monitorea la lista de correo? Para SLF, ¿con qué frecuencia se monitorea su codeplex? ¿Dónde se clasifica la prioridad de estos proyectos "gratuitos" en comparación con los empleos remunerados de los desarrolladores? ¿Puede permitirse una abstracción de terceros para implementar una característica que necesita? ¿Serán receptivos si implementan algo y luego lo envían nuevamente para que se incluya en el producto?

En el lado positivo, está disponible toda la fuente de todas estas abstracciones, por lo que podría asumir la responsabilidad y realizar cualquier corrección o agregar cualquier mejora que usted, sin tener que pasar por el tiempo y la energía de creando una abstracción desde cero. ¿Le gusta Common.Logging pero realmente quiere log4net/NLog GDC/MDC/NDC? Obtenga la implementación de Castle y agréguela a Common.Logging. Voila! Una abstracción de registro que contiene casi el 100% de la API de registro log4net/NLog. ¿Prefiere SLF pero desearía tener IsXXXEnabled? No hay mucho trabajo para implementar eso. Continúe y vire en el GDC/MDC/NDC mientras lo hace. ¿Te gusta Castle? (No estoy tan familiarizado con eso, no estoy seguro de lo fácil que es usarlo fuera de Castle, si eso es importante) Tenga cuidado, no lo he usado, pero mirando la fuente en git, parece que el registrador NLog abstracción podría no conservar la información del sitio de llamada.

¿Es ético tomar partes de múltiples proyectos de código abierto y combinarlos para hacer un proyecto "super" (para su propio uso o el de su compañía)? ¿Es malo tomar Common.Logging y aumentarlo con la implementación de Castle GDC/MDC/NDC? No lo sé. Dejaré que alguien más responda eso.

Estoy casi terminado ...

Algunos terceros abstracciones de registro Parte proporcione otras capacidades. Puede usar una biblioteca que se implemente en términos de, digamos log4net. Es posible que no desee usar log4net, o al menos no desee estar vinculado a él. Common.Logging (y tal vez SLF) hace que sea relativamente fácil para usted capturar los mensajes de log4net logging y redirigirlos a través de la abstracción para que sean capturados en la corriente de registro subyacente del marco de registro de la abstracción. SLF podría proporcionar algo similar. Por supuesto, es posible que pueda hacer algo similar con los marcos de registro existentes, ya sea de manera inmediata o escribiendo un apéndice log4net personalizado, NLog Target o System.Diagnostics TraceListener. Estas características no han brotado muy alto en mi evaluación particular de si usar o no una abstracción de registro de terceros en mi proyecto porque estoy interesado principalmente simplemente en el aspecto de la abstracción.

Entonces, ¿dónde estoy parado? Creo que tiene sentido mantener el código de su aplicación aislado de un marco de registro específico. Para mí, Common.Logging parece una opción sólida de abstracción, aunque faltan algunas características importantes (GDC/MDC/NDC) y no es compatible con Silverlight. Sería genial de esas características disponibles pronto. Me siento cómodo con la implementación de GDC/MDC/NDC si es necesario. Hacerlo compatible con Silverlight probablemente requeriría más esfuerzo, principalmente porque no tengo mucha experiencia con C# /. NET/Silverlight. Hasta que se solucionen esos problemas, podríamos escribir un montón de código de aplicación con Common.Logging en su lugar. Podemos dedicar nuestro tiempo a desarrollar nuestra aplicación en lugar de desarrollar otra biblioteca de registro o biblioteca de abstracción. Si terminamos teniendo que agregar esas características faltantes nosotros mismos, bueno, habríamos tenido que hacer mucho de eso si hubiésemos implementado una biblioteca de registro o una biblioteca de abstracción nosotros mismos.

+3

¡Una publicación tan masiva! Estoy de acuerdo con todo, +1 ciertamente, pero tal vez podría ser simplificado/formateado un poco? Puedo ver muchas cosas declaradas varias veces, por ejemplo. Además, como esto es muy antiguo, ¿tiene alguna idea más reciente sobre esto? ¿Ha cambiado algo mientras tanto que justificaría discutir de nuevo? – julealgon

+1

No tengo nada que agregar desde mi publicación original. En el momento en que escribí esto, estaba en la agonía de aprender tanto sobre la tala como pude. En el caso de mi organización, decidimos utilizar el enfoque de fachada de registro, específicamente Common.Logging para .Net. También nos decidimos por NLog como nuestro sistema de registro subyacente, aunque, debido a la fachada, no dependemos directamente de NLog. – wageoghe

+0

FWIW: Recientemente tropecé con un [LibLog] (http://dhickey.ie/2015/04/introducing-liblog/) que es solo un archivo y no una dependencia. – LosManos

0

En este ejemplo, solo necesita un nivel de abstracción para poder intercambiar su registrador.

¿Qué ventaja adicional sería poder cambiar su fachada de registro?

+0

Si apareciera una mejor fachada de explotación maderera o si el proyecto de la fachada de tala se agotara, podría cambiarlo. – brian

+0

:) Es cierto, pero en mi humilde opinión YAGNI, y de todos modos a veces tienes que aceptar que en algún momento en el futuro tendrás que abrir el editor de código y hacer algunos cambios. Dicho eso, si crees que tienes necesidad, hazlo. Pero nunca quiero ver un proyecto de fachadas de fachada de fachada de registro de terceros ... –

1

No es el número mágico, depende de lo flexible que quieras ser. Si piensa cambiar la fachada del registro un día, debe escribir una fachada. Si piensa cambiar solo el registro, necesita una fachada. Si no piensas en nada, no uses fachada.

La desventaja como dijiste son las habilidades especiales. Si los está usando, escriba su propia fachada solamente.

9

Creo que lo que hace Uno (nivel de abstracción) el número mágico aquí es que Zero es muy pocos y Dos es demasiado.

El intercambio de un registrador detrás de una fachada de registrador (número de niveles: 1) puede resultar en algún beneficio para el usuario, como que el nuevo registrador puede hacer algo que el registrador anterior no puede. Me imagino que podría ser el rendimiento, admitir ciertos tipos de apéndices, etc.

Es mucho más difícil imaginar que el usuario se beneficie al cambiar una fachada de registrador (número de niveles: 2).

(Y si el número de niveles es 0, entonces es probable que sea un mal diseño orientado a objetos: tendrá miles de lugares donde se hace referencia al registrador y qué pasa si hay un cambio brusco en la próxima versión del registrador.)

El trato con fachadas de registrador parece ser que tiene que elegir una de las opciones de terceros o crear la suya propia y prepararse para quedarse con ella durante mucho tiempo.

3

Hasta que NLog y log4net proporcionen una interfaz que se pueda utilizar en lugar de las clases concretas, siempre las resumí detrás de mi propia interfaz y clase contenedora.

¿Por qué?

Para obtener la mayor cobertura de prueba de todos los requisitos del usuario, especialmente cuando esos requisitos cubren el registro.

Cuando tiene todo su registro pasando por una interfaz en lugar de una clase concreta, se vuelve muy fácil proporcionar un objeto simulado con la interfaz de registro (elija su elección de cómo hacerlo, inyección de dependencia, etc.) para registrar todas las llamadas de registro realizadas durante un escenario de prueba en particular.

Esto se puede afirmar y si un cambio de código interrumpe el registro, las pruebas de la unidad lo cubrirán.

Si NLog o log4Net tuvieran que proporcionar una interfaz para sus registradores, entonces no tendría que hacer el esfuerzo de proporcionar una interfaz y una clase contenedora, ya que podría burlarme de su interfaz para las pruebas.

0

Se puede utilizar en el protocolo para el sistema de complementos. En lugar de decir use Some3rdParty.dll and MyPlugingApi.dll, solo documentaría MyPlugingApi.dll. La interfaz de la fachada del registro sugerirá y documentará algún uso que probablemente genere registros legibles y un rendimiento logístico suficientemente bueno. Y, por supuesto, hacer cambios no generará cambios en la API de complementos.

¿Por qué hay que cambiar la implementación?Esto puede suceder si la corriente parece ralentizarse para comenzar a salir de la configuración o ralentizar la escritura de entradas, desea expandirse para reducir la versión de .NET que no necesita una tercera parte, integrándola con otra base de código que utiliza otros grabadores de registro.

También he escrito otra facade que es hija de pensamientos en esta respuesta.

1

En mi proyecto utilizo System.Diagnostics.Trace.TraceError(...), System.Diagnostics.Debug.Print(...) como fachada para el registro. Para organizar registros (de escritura) uso NLog, es decir, en app.config tengo la configuración para NLog y la redirección del seguimiento de .net a NLog.

<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
    <targets> 
    <target name="file" xsi:type="File" 
     layout="${longdate:universalTime=true}Z [${threadid}] ${pad:padding=5:inner=${level:uppercase=true}} ${logger} ${message}" 
     fileName="${basedir}/App_Data/logfile.txt"... 
    </targets> 
</nlog> 
<system.diagnostics> 
    <trace> 
    <listeners> 
     <add name="nlog" type="NLog.NLogTraceListener, NLog" /> 
    </listeners> 
    </trace> 
</system.diagnostics> 

Esto no me agrupa a ningún registrador. Cuando envío mis componentes a los clientes, pueden usar cualquier registrador que quieran. Usar un registrador particular en la aplicación podría causar problemas, es decir, puede usar nlog pero sus clientes usan log4net.

0

De ninguna manera soy un experto, pero en nuestro grupo, el valor de la fachada no nos da la capacidad de cambiar el marco de trabajo. Es cierto, eso es algo que obtenemos, pero estamos en la categoría que es muy poco probable que cambie nuestro marco.

En nuestro caso, estamos utilizando una fachada para adaptar la interfaz de registro a las necesidades de nuestra aplicación. Descubrimos que en todos los marcos semánticos que vimos, todavía estaban demasiado concentrados en lo que llamamos el modelo de registro "forense": alguien que busca entre los registros la búsqueda de alguna línea de salida para analizar algún evento.

Si bien este es un caso de uso para nosotros también, en realidad no es nuestro caso de uso principal. Queremos más de un instrumentación marco de registro, que nos permitirá informar sobre cosas de interés, incluso aquellas que no hemos pensado en el momento de la implementación.

Por ejemplo, nuestra aplicación no necesita un "mensaje" para acompañar un evento; en cambio, nuestro "registrador" aceptará enumeraciones que definan el tipo de evento y los objetos de estado que representan detalles específicos (por ejemplo, marcas de tiempo u otros valores) y los serializará para facilitar informes, análisis de rendimiento, métricas de valor empresarial, etc., además de respaldar los forense. (Reconocemos que estamos, de hecho, haciendo que los forenses tradicionales sean un poco más difíciles en beneficio de una interfaz de registro fácil de usar y comprender que aumenta la probabilidad de que realmente la usemos y la usemos con más frecuencia).

Para darle una respuesta resumida de manera sucinta, aquí hay un orden aproximado de los beneficios que creemos que obtendremos al utilizar una fachada de registro.

  1. interfaz consistente, especialmente diseñada facilitar la instrumentación (en oposición a la tala simplemente tradicional, como se mencionó anteriormente)
  2. puntos de prueba mockable
  3. implementaciones registrador inyectables adecuado para todo, desde el desarrollo local a las conexiones AWS S3 o DB, dependiendo de la implementación (nuestra aplicación utiliza Autofac con inyección de dependencia de constructor)
  4. Substituto table logger frameworks que nos permite cambiar a un marco logger diferente en el futuro si queremos. (Por cierto, no prevemos que esto ocurra, por lo que, por sí solo, no nos habría convencido de usar una fachada.)

Y finalmente, 0 fachadas perderían estos beneficios, y 2 fachadas no se agregarían a ninguno de estos beneficios, por eso 1 fachada es el número correcto para nosotros.

Gran pregunta, @brian! :)

1

Un uso importante de una fachada de registro es cuando está escribiendo una biblioteca. Incrustar dependencias en una biblioteca siempre es algo que requiere un poco de cuidado, y aún más.

En resumen, no desea forzar su implementación de registro a los usuarios de su biblioteca. Usar una fachada bien elegida significa que podrán manejar los registros de su biblioteca con su propio marco de trabajo y no tendrán que pasar por algunas extrañas exclusiones de dependencia y lagunas para que coexistan tanto su marco de trabajo como el de ellos.