Configurações de NLog mais úteis [fechadas]

Quais são as melhores ou mais úteis configurações para registar com o Blog? (Estes podem ser simples ou complexos, desde que sejam úteis.)

estou a pensar em exemplos como a introdução automática de ficheiros de registo num determinado tamanho, a alteração do layout (mensagem de Registo) quer exista ou não uma excepção, a escalada do nível de Registo, uma vez que ocorreu um erro, etc.

Aqui estão alguns links:

Author: Taryn, 2010-11-03

10 answers

Algumas destas incluem-se na categoria de dicas gerais do NLog (ou logging) em vez de sugestões de configuração estrita.

Aqui estão alguns links gerais de registro daqui em SO (você pode ter visto alguns ou todos estes já):

Log4net vs. Nlog

Registar as melhores práticas

Para que serve uma fachada madeireira?

Por que os madeireiros recomendam usar um madeireiro por classe?

Utilizar o padrão comum de nomear o seu logger com base na classe Logger logger = LogManager.GetCurrentClassLogger(). Isso lhe dá um alto grau de granularidade em seus madeireiros e lhe dá uma grande flexibilidade na configuração dos madeireiros (controle globalmente, pelo namespace, pelo nome específico do madeireiro, etc).

Utilizar madeireiros não baseados em nomes de classes, quando apropriado. Talvez você tenha uma função para a qual você realmente quer controlar o registro separadamente. Talvez você tenha algumas preocupações transversais de registro (desempenho log).

Se não usar o registo baseado no nome da classe, considere nomear os seus madeireiros em algum tipo de estrutura hierárquica (talvez por área funcional) para que possa manter maior flexibilidade na sua configuração. Por exemplo, você pode ter uma área funcional "banco de dados", uma "análise" FA, e uma "ui" FA. Cada uma delas pode ter sub-áreas. Então, você pode pedir madeireiros como este:

Logger logger = LogManager.GetLogger("Database.Connect");
Logger logger = LogManager.GetLogger("Database.Query");
Logger logger = LogManager.GetLogger("Database.SQL");
Logger logger = LogManager.GetLogger("Analysis.Financial");
Logger logger = LogManager.GetLogger("Analysis.Personnel");
Logger logger = LogManager.GetLogger("Analysis.Inventory");
E assim por diante. Com os loggers hierárquicos, poderá configurar o registo globalmente (a "*"or root logger), by FA (Database, Analysis, UI), or by subarea (Database.Conecte, etc).

Os madeireiros têm muitas opções de configuração:

<logger name="Name.Space.Class1" minlevel="Debug" writeTo="f1" /> 
<logger name="Name.Space.Class1" levels="Debug,Error" writeTo="f1" /> 
<logger name="Name.Space.*" writeTo="f3,f4" />
<logger name="Name.Space.*" minlevel="Debug" maxlevel="Error" final="true" /> 

Veja a ajuda do NLog para mais informações sobre exactamente o que cada uma das opções significa. Provavelmente, os itens mais notáveis aqui são a capacidade de regras de logger de caracteres especiais, o conceito de que várias regras de logger pode "executar" para uma única declaração de registro, e que uma regra de logger pode ser marcada como "final" para que as regras subsequentes não executar para uma dada declaração de Registo.

Use o contexto GlobalDiagnosticContext, MappedDiagnosticContext, e NestedDiagnosticContext para adicionar um contexto adicional à sua saída.

Use "variável" no seu ficheiro de configuração para simplificar. Por exemplo, você pode definir variáveis para seus layouts e, em seguida, referenciar a variável na configuração de destino, em vez de especificar o layout diretamente.

  <variable name="brief" value="${longdate} | ${level} | ${logger} | ${message}"/>
  <variable name="verbose" value="${longdate} | ${machinename} | ${processid} | ${processname} | ${level} | ${logger} | ${message}"/>
  <targets>
    <target name="file" xsi:type="File" layout="${verbose}" fileName="${basedir}/${shortdate}.log" />
    <target name="console" xsi:type="ColoredConsole" layout="${brief}" />
  </targets>

Ou, você poderia criar um conjunto" personalizado " de propriedades para adicionar a um esquema.

  <variable name="mycontext" value="${gdc:item=appname} , ${mdc:item=threadprop}"/>
  <variable name="fmt1withcontext" value="${longdate} | ${level} | ${logger} | [${mycontext}] |${message}"/>
  <variable name="fmt2withcontext" value="${shortdate} | ${level} | ${logger} | [${mycontext}] |${message}"/>

Ou, você pode fazer coisas como criar "day" ou "month" layout renderers estritamente através da configuração:

  <variable name="day" value="${date:format=dddd}"/>
  <variable name="month" value="${date:format=MMMM}"/>
  <variable name="fmt" value="${longdate} | ${level} | ${logger} | ${day} | ${month} | ${message}"/>
  <targets>
    <target name="console" xsi:type="ColoredConsole" layout="${fmt}" />
  </targets>

Também pode usar as renders de layout para definir o seu nome de ficheiro:

  <variable name="day" value="${date:format=dddd}"/>
  <targets>
    <target name="file" xsi:type="File" layout="${verbose}" fileName="${basedir}/${day}.log" />
  </targets>
Se rodar o seu ficheiro diariamente, cada ficheiro pode chamar-se "Segunda-feira".log", " terça-feira.log", etc. Não tenhas medo de escrever o teu próprio renderizador. É fácil e permite-lhe adicionar a sua própria informação de contexto ao ficheiro de registo através da configuração. Por exemplo, aqui está um renderizador de layout (baseado no NLog 1.x, não 2.0) que pode adicionar o traço.Correlacionador.ActivityId to the log:
  [LayoutRenderer("ActivityId")]
  class ActivityIdLayoutRenderer : LayoutRenderer
  {
    int estimatedSize = Guid.Empty.ToString().Length;

    protected override void Append(StringBuilder builder, LogEventInfo logEvent)
    {
      builder.Append(Trace.CorrelationManager.ActivityId);
    }

    protected override int GetEstimatedBufferSize(LogEventInfo logEvent)
    {
      return estimatedSize;
    }
  }

Diga ao NLog onde estão as suas extensões de NLog (que conjunto) como esta:

  <extensions>
    <add assembly="MyNLogExtensions"/>
  </extensions>

Usar o renderizador de layout personalizado desta forma:

  <variable name="fmt" value="${longdate} | ${ActivityId} | ${message}"/>

Usar alvos async:

<nlog>
  <targets async="true">
    <!-- all targets in this section will automatically be asynchronous -->
  </targets>
</nlog>

E invólucros de alvo predefinidos:

<nlog>  
  <targets>  
    <default-wrapper xsi:type="BufferingWrapper" bufferSize="100"/>  
    <target name="f1" xsi:type="File" fileName="f1.txt"/>  
    <target name="f2" xsi:type="File" fileName="f2.txt"/>  
  </targets>  
  <targets>  
    <default-wrapper xsi:type="AsyncWrapper">  
      <wrapper xsi:type="RetryingWrapper"/>  
    </default-wrapper>  
    <target name="n1" xsi:type="Network" address="tcp://localhost:4001"/>  
    <target name="n2" xsi:type="Network" address="tcp://localhost:4002"/>  
    <target name="n3" xsi:type="Network" address="tcp://localhost:4003"/>  
  </targets>  
</nlog>

Se for caso disso. Veja os documentos do NLog para mais informações sobre eles.

Diga ao NLog para vigiar e recarregar automaticamente o configuração se mudar:

<nlog autoReload="true" /> 

Existem várias opções de configuração para ajudar com a resolução de problemas no Blog

<nlog throwExceptions="true" />
<nlog internalLogFile="file.txt" />
<nlog internalLogLevel="Trace|Debug|Info|Warn|Error|Fatal" />
<nlog internalLogToConsole="false|true" />
<nlog internalLogToConsoleError="false|true" />

Veja a ajuda do NLog para mais informações.

O NLog 2. 0 adiciona invólucros de formador de layout que permitem que o processamento adicional seja realizado no resultado de um renderizador de layout (tais como a remoção de espaços em branco, maiúsculas, minúsculas, etc.).

Não tenha medo de embrulhar o logger se quiser isolar o seu código a partir de uma dependência difícil do 'NLog', mas embrulhe correctamente. Existem exemplos de como terminar no repositório de github do NLog. Outra razão para a mudança de linha pode ser que você queira adicionar automaticamente informações de contexto específicas a cada mensagem registrada (colocando-a no LogEventInfo.Contexto).

Existem prós e contras para enroscar (ou abstrair) o NLog (ou qualquer outra estrutura de registo para esse assunto). Com um pouco de esforço, você pode encontrar muita informação aqui, assim apresentando ambos os lados.

Se está a considerar embrulhar, considere a utilização de comum.Logging . Ele funciona muito bem e permite que você facilmente mudar para outro framework de registro, se você quiser fazer isso. Além disso, se estiver a considerar embrulhar, pense em como irá lidar com os objectos de contexto (GDC, MDC, NDC). Comum.O Logging não suporta atualmente uma abstração para eles, mas está supostamente na fila de recursos para adicionar.

 373
Author: wageoghe, 2017-12-13 06:36:06

Tratar as excepções de forma diferente

Muitas vezes queremos obter mais informações quando há uma excepção. A seguinte configuração tem dois alvos, um arquivo e a consola, que filtram se há ou não alguma informação de exceção. (EDIT: Jarek postou sobre um novo método de fazer isso no vNext .)

A chave é ter um alvo embrulhado com xsi:type="FilteringWrapper" condition="length('${exception}')>0"

<nlog xmlns="http://www.nlog-project.org/schemas/NLog.mono2.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      autoReload="true"
      internalLogLevel="Warn"
      internalLogFile="nlog log.log"
      >
    <variable name="VerboseLayout" 
              value="${longdate} ${level:upperCase=true} ${message}  
                    (${callsite:includSourcePath=true})"            />
    <variable name="ExceptionVerboseLayout"  
              value="${VerboseLayout} (${stacktrace:topFrames=10})  
                     ${exception:format=ToString}"                  />

    <targets async="true">
        <target name="file" xsi:type="File" fileName="log.log"
                layout="${VerboseLayout}">
        </target>

        <target name="fileAsException"  
                xsi:type="FilteringWrapper" 
                condition="length('${exception}')>0">
            <target xsi:type="File"  
                    fileName="log.log"  
                    layout="${ExceptionVerboseLayout}" />
        </target>

        <target xsi:type="ColoredConsole"
                name="console"
                layout="${NormalLayout}"/>

        <target xsi:type="FilteringWrapper"  
                condition="length('${exception}')>0"  
                name="consoleException">
            <target xsi:type="ColoredConsole" 
                    layout="${ExceptionVerboseLayout}" />
        </target>
    </targets>

    <rules>
        <logger name="*" minlevel="Trace" writeTo="console,consoleException" />
        <logger name="*" minlevel="Warn" writeTo="file,fileAsException" />
    </rules>

</nlog>
 61
Author: Pat, 2014-06-09 23:28:32

Aparentemente, agora pode usarO Blog com Growl para o Windows .

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

    <extensions>
        <add assembly="NLog.Targets.GrowlNotify" />
    </extensions>

    <targets>
        <target name="growl" type="GrowlNotify" password="" host="" port="" />
    </targets>

    <rules>
        <logger name="*" minLevel="Trace" appendTo="growl"/>
    </rules>

</nlog>

NLog with Growl for WindowsNLog trace message with Growl for WindowsNLog debug message with Growl for WindowsNLog info message with Growl for WindowsNLog warn message with Growl for WindowsNLog error message with Growl for WindowsNLog fatal message with Growl for Windows

 58
Author: Çağdaş Tekin, 2011-06-29 03:42:26

Configurar o NLog via XML, mas programaticamente

O quê? Sabia que pode especificar o XML do NLog directamente para o NLog da sua aplicação, em vez de o ter lido do ficheiro de configuração? Bem, tu podes. Vamos dizer que você tem um aplicativo distribuído e você quer usar a mesma configuração em todos os lugares. Você poderia manter um arquivo de configuração em cada local e mantê-lo separadamente, você poderia manter um em um local central e empurrá-lo para os locais de satélite, ou podes fazer muitas outras coisas. Ou, você pode armazenar seu XML em uma base de dados, obtê-lo no arranque da aplicação, e configurar o NLog diretamente com esse XML (talvez checando periodicamente para ver se ele tinha mudado).
  string xml = @"<nlog>
                   <targets>
                     <target name='console' type='Console' layout='${message}' />
                   </targets>

                   <rules>
                     <logger name='*' minlevel='Error' writeTo='console' />
                   </rules>
                 </nlog>";

  StringReader sr = new StringReader(xml);
  XmlReader xr = XmlReader.Create(sr);
  XmlLoggingConfiguration config = new XmlLoggingConfiguration(xr, null);
  LogManager.Configuration = config;
  //NLog is now configured just as if the XML above had been in NLog.config or app.config

  logger.Trace("Hello - Trace"); //Won't log
  logger.Debug("Hello - Debug"); //Won't log
  logger.Info("Hello - Info");   //Won't log
  logger.Warn("Hello - Warn");   //Won't log
  logger.Error("Hello - Error"); //Will log
  logger.Fatal("Hello - Fatal"); //Will log

  //Now let's change the config (the root logging level) ...
  string xml2 = @"<nlog>
                  <targets>
                     <target name='console' type='Console' layout='${message}' />
                   </targets>

                   <rules>
                     <logger name='*' minlevel='Trace' writeTo='console' />
                   </rules>
                 </nlog>";

  StringReader sr2 = new StringReader(xml2);
  XmlReader xr2 = XmlReader.Create(sr2);
  XmlLoggingConfiguration config2 = new XmlLoggingConfiguration(xr2, null);
  LogManager.Configuration = config2;

  logger.Trace("Hello - Trace"); //Will log
  logger.Debug("Hello - Debug"); //Will log
  logger.Info("Hello - Info");   //Will log
  logger.Warn("Hello - Warn");   //Will log
  logger.Error("Hello - Error"); //Will log
  logger.Fatal("Hello - Fatal"); //Will log

Não tenho a certeza do quão robusto isto é, mas este exemplo fornece um ponto de partida útil para as pessoas que possam querer tentar configurar desta forma.

 27
Author: wageoghe, 2010-11-23 19:44:38

Registar níveis diferentes dependendo se há ou não um erro

Este exemplo permite-lhe obter mais informações quando há um erro no seu código. Basicamente, ele buffers de mensagens e resultados apenas aqueles em um determinado nível de log (por exemplo, Avisar) a menos que uma determinada condição seja atendida (por exemplo, lá foi um erro, para o nível de log é >= Erro), então, com a saída de mais informações (e.g. todas as mensagens de níveis de log >= Trace). Porque as mensagens são tamponadas, isto permite você recolhe informações sobre o que aconteceu antes de {[10] } um erro ou Errorexecção ter sido registado - muito útil!

Adaptei este de um exemplo no código-fonte. Eu fui jogado no início porque eu deixei de fora o {[[1]} (uma vez que o meu não é um app ASP) - acontece que o PostFilteringWrapper requer algum alvo buffer. Note que o elemento target-ref usado no exemplo ligado acima não pode ser usado no NLog 1.0 (estou a usar o Refresh 1.0 para um. NET 4.0 app); é necessário colocar o seu alvo dentro do bloco de embrulho. Note também que a sintaxe lógica (ou seja, maior ou menor que Símbolos, ) tem que usar os símbolos, não o XML escapa para esses símbolos (ou seja &gt; e &lt;) ou então o NLog irá errar.

App.configuração:

<?xml version="1.0"?>
<configuration>
    <configSections>
        <section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog"/>
    </configSections>

    <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          throwExceptions="true" internalLogToConsole="true" internalLogLevel="Warn" internalLogFile="nlog.log">
        <variable name="appTitle" value="My app"/>
        <variable name="csvPath" value="${specialfolder:folder=Desktop:file=${appTitle} log.csv}"/>

        <targets async="true">
            <!--The following will keep the default number of log messages in a buffer and write out certain levels if there is an error and other levels if there is not. Messages that appeared before the error (in code) will be included, since they are buffered.-->
            <wrapper-target xsi:type="BufferingWrapper" name="smartLog">
                <wrapper-target xsi:type="PostFilteringWrapper">
                    <!--<target-ref name="fileAsCsv"/>-->
                    <target xsi:type="File" fileName="${csvPath}"
                    archiveAboveSize="4194304" concurrentWrites="false" maxArchiveFiles="1" archiveNumbering="Sequence"
                    >
                        <layout xsi:type="CsvLayout" delimiter="Tab" withHeader="false">
                            <column name="time" layout="${longdate}" />
                            <column name="level" layout="${level:upperCase=true}"/>
                            <column name="message" layout="${message}" />
                            <column name="callsite" layout="${callsite:includeSourcePath=true}" />
                            <column name="stacktrace" layout="${stacktrace:topFrames=10}" />
                            <column name="exception" layout="${exception:format=ToString}"/>
                            <!--<column name="logger" layout="${logger}"/>-->
                        </layout>
                    </target>

                     <!--during normal execution only log certain messages--> 
                    <defaultFilter>level >= LogLevel.Warn</defaultFilter>

                     <!--if there is at least one error, log everything from trace level--> 
                    <when exists="level >= LogLevel.Error" filter="level >= LogLevel.Trace" />
                </wrapper-target>
            </wrapper-target>

        </targets>

        <rules>
            <logger name="*" minlevel="Trace" writeTo="smartLog"/>
        </rules>
    </nlog>
</configuration>
 22
Author: Pat, 2010-11-19 15:53:40

Eu dei algumas respostas razoavelmente interessantes para esta pergunta:

Secção do cabeçalho Gerador de 'Nlog' para um ficheiro de Registo

Adicionar um cabeçalho:

A pergunta queria saber como adicionar um cabeçalho ao ficheiro de Registo. Se usar itens de configuração como este, poderá definir o formato do cabeçalho separadamente do formato do resto dos itens do registo. Use um único logger, talvez chamado de "headerlogger" para registrar uma única mensagem no início do aplicação e você obter o seu cabeçalho:

Defina o cabeçalho e as disposições dos ficheiros:

  <variable name="HeaderLayout" value="This is the header.  Start time = ${longdate} Machine = ${machinename} Product version = ${gdc:item=version}"/>
  <variable name="FileLayout" value="${longdate} | ${logger} | ${level} | ${message}" />

Define os alvos usando os esquemas:

<target name="fileHeader" xsi:type="File" fileName="xxx.log" layout="${HeaderLayout}" />
<target name="file" xsi:type="File" fileName="xxx.log" layout="${InfoLayout}" />

Define os madeireiros:

<rules>
  <logger name="headerlogger" minlevel="Trace" writeTo="fileHeader" final="true" />
  <logger name="*" minlevel="Trace" writeTo="file" />
</rules>

Escreva o cabeçalho, provavelmente no início do programa:

  GlobalDiagnosticsContext.Set("version", "01.00.00.25");

  LogManager.GetLogger("headerlogger").Info("It doesn't matter what this is because the header format does not include the message, although it could");
Esta é, em grande parte, apenas outra versão da ideia de "tratar as excepções de forma diferente".

Registar cada nível de registo com uma disposição diferente

Da mesma forma, o cartaz queria saber como mudar o formato por Registo nivel. Não estava claro para mim qual era o objetivo final (e se ele poderia ser alcançado de uma forma" melhor"), mas eu era capaz de fornecer uma configuração que fez o que ele pediu:

  <variable name="TraceLayout" value="This is a TRACE - ${longdate} | ${logger} | ${level} | ${message}"/> 
  <variable name="DebugLayout" value="This is a DEBUG - ${longdate} | ${logger} | ${level} | ${message}"/> 
  <variable name="InfoLayout" value="This is an INFO - ${longdate} | ${logger} | ${level} | ${message}"/> 
  <variable name="WarnLayout" value="This is a WARN - ${longdate} | ${logger} | ${level} | ${message}"/> 
  <variable name="ErrorLayout" value="This is an ERROR - ${longdate} | ${logger} | ${level} | ${message}"/> 
  <variable name="FatalLayout" value="This is a FATAL - ${longdate} | ${logger} | ${level} | ${message}"/> 
  <targets> 
    <target name="fileAsTrace" xsi:type="FilteringWrapper" condition="level==LogLevel.Trace"> 
      <target xsi:type="File" fileName="xxx.log" layout="${TraceLayout}" /> 
    </target> 
    <target name="fileAsDebug" xsi:type="FilteringWrapper" condition="level==LogLevel.Debug"> 
      <target xsi:type="File" fileName="xxx.log" layout="${DebugLayout}" /> 
    </target> 
    <target name="fileAsInfo" xsi:type="FilteringWrapper" condition="level==LogLevel.Info"> 
      <target xsi:type="File" fileName="xxx.log" layout="${InfoLayout}" /> 
    </target> 
    <target name="fileAsWarn" xsi:type="FilteringWrapper" condition="level==LogLevel.Warn"> 
      <target xsi:type="File" fileName="xxx.log" layout="${WarnLayout}" /> 
    </target> 
    <target name="fileAsError" xsi:type="FilteringWrapper" condition="level==LogLevel.Error"> 
      <target xsi:type="File" fileName="xxx.log" layout="${ErrorLayout}" /> 
    </target> 
    <target name="fileAsFatal" xsi:type="FilteringWrapper" condition="level==LogLevel.Fatal"> 
      <target xsi:type="File" fileName="xxx.log" layout="${FatalLayout}" /> 
    </target> 
  </targets> 


    <rules> 
      <logger name="*" minlevel="Trace" writeTo="fileAsTrace,fileAsDebug,fileAsInfo,fileAsWarn,fileAsError,fileAsFatal" /> 
      <logger name="*" minlevel="Info" writeTo="dbg" /> 
    </rules> 

Novamente, muito semelhante a tratar as excepções de forma diferente.

 21
Author: wageoghe, 2017-05-23 10:31:18

Logar no Twitter

Com base em este post sobre um aplicativo de log4net no Twitter , pensei em tentar a minha mão para escrever um alvo no Blog do Twitter (usando a actualização do NLog 1.0, não a versão 2.0). Infelizmente, até agora eu não tenho sido capaz de obter um Tweet para realmente postar com sucesso. Não sei se há algo de errado no meu código, no Twitter, na ligação à internet da nossa empresa/firewall, ou o quê. Estou a postar o código aqui no caso de alguém estar interessado em experimentá-lo. Note que ali são três métodos diferentes de "Post". O primeiro que experimentei foi o PostMessageToTwitter. PostMessageToTwitter é essencialmente o mesmo que PostLoggingEvent no post orignal. Se usar isso, terei uma excepção 401. PostMessageBasic recebe a mesma exceção. O PostMessage é executado sem erros, mas a mensagem ainda não compensa o Twitter. PostMessage and PostMessageBasic are based on examples that I found here on SO.

FYI {[[6]} - acabei de encontrar um comentário de @Jason Diller para uma resposta em Este post que diz que o twitter vai desligar a Autenticação Básica "no próximo mês". Isto foi em maio de 2010 e estamos agora em dezembro de 2010, por isso acho que pode ser por isso que isto não está a funcionar.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Web;
using System.IO;

using NLog;
using NLog.Targets;
using NLog.Config;

namespace NLogExtensions
{
  [Target("TwitterTarget")]
  public class TwitterTarget : TargetWithLayout
  {
    private const string REQUEST_CONTENT_TYPE = "application/x-www-form-urlencoded";  

    private const string REQUEST_METHOD = "POST";  

    // The source attribute has been removed from the Twitter API,  
    // unless you're using OAuth.  
    // Even if you are using OAuth, there's still an approval process.  
    // Not worth it; "API" will work for now!  
    // private const string TWITTER_SOURCE_NAME = "Log4Net";  
    private const string TWITTER_UPDATE_URL_FORMAT = "http://twitter.com/statuses/update.xml?status={0}";  

    [RequiredParameter]
    public string TwitterUserName { get; set; }

    [RequiredParameter]
    public string TwitterPassword { get; set; }

    protected override void Write(LogEventInfo logEvent)
    {
      if (string.IsNullOrWhiteSpace(TwitterUserName) || string.IsNullOrWhiteSpace(TwitterPassword)) return;

      string msg = this.CompiledLayout.GetFormattedMessage(logEvent);

      if (string.IsNullOrWhiteSpace(msg)) return;

      try
      {
        //PostMessageToTwitter(msg);
        PostMessageBasic(msg);
      }
      catch (Exception ex)
      {
        //Should probably do something here ...
      }
    }

    private void PostMessageBasic(string msg)
    {
      // Create a webclient with the twitter account credentials, which will be used to set the HTTP header for basic authentication 
      WebClient client = new WebClient { Credentials = new NetworkCredential { UserName = TwitterUserName, Password = TwitterPassword } };

      // Don't wait to receive a 100 Continue HTTP response from the server before sending out the message body 
      ServicePointManager.Expect100Continue = false;

      // Construct the message body 
      byte[] messageBody = Encoding.ASCII.GetBytes("status=" + msg);

      // Send the HTTP headers and message body (a.k.a. Post the data) 
      client.UploadData(@"http://twitter.com/statuses/update.xml", messageBody);
    }

    private void PostMessage(string msg)
    {
      string user = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(TwitterUserName + ":" + TwitterPassword));
      byte [] bytes = System.Text.Encoding.UTF8.GetBytes("status=" + msg.ToTweet());
      HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://twitter.com/statuses/update.xml");
      request.Method = "POST";
      request.ServicePoint.Expect100Continue = false;
      request.Headers.Add("Authorization", "Basic " + user);
      request.ContentType = "application/x-www-form-urlencoded";
      request.ContentLength = bytes.Length;
      Stream reqStream = request.GetRequestStream();
      reqStream.Write(bytes, 0, bytes.Length);
      reqStream.Close();
    }

    private void PostMessageToTwitter(string msg)
    {
      var updateRequest = HttpWebRequest.Create(string.Format(TWITTER_UPDATE_URL_FORMAT,
                                                HttpUtility.UrlEncode(msg.ToTweet()))) as HttpWebRequest;
      updateRequest.ContentLength = 0;
      updateRequest.ContentType = REQUEST_CONTENT_TYPE;
      updateRequest.Credentials = new NetworkCredential(TwitterUserName, TwitterPassword);
      updateRequest.Method = REQUEST_METHOD;

      updateRequest.ServicePoint.Expect100Continue = false;

      var updateResponse = updateRequest.GetResponse() as HttpWebResponse;

      if (updateResponse.StatusCode != HttpStatusCode.OK && updateResponse.StatusCode != HttpStatusCode.Continue)
      {
        throw new Exception(string.Format("An error occurred while invoking the Twitter REST API [Response Code: {0}]", updateResponse.StatusCode));
      }
    }
  }

  public static class Extensions
  {
    public static string ToTweet(this string s)
    {
      if (string.IsNullOrEmpty(s) || s.Length < 140)
      {
        return s;
      }

      return s.Substring(0, 137) + "...";
    }
  }
}

Configure-o assim:

Diga ao NLog que o conjunto contém o alvo:

<extensions>
  <add assembly="NLogExtensions"/>
</extensions>

Configure o alvo:

<targets>
    <target name="twitter" type="TwitterTarget" TwitterUserName="yourtwittername" TwitterPassword="yourtwitterpassword" layout="${longdate} ${logger} ${level} ${message}" />
</targets>
Se alguém tentar isto e tiver sucesso, postem as vossas descobertas.
 10
Author: wageoghe, 2017-05-23 12:34:58

Apresentação de relatórios a um sítio Web / Base de dados externo

Eu queria uma maneira simples e automática de relatar erros (uma vez que os usuários muitas vezes não) de nossas aplicações. A solução mais fácil que eu poderia vir acima com era uma URL pública - uma página web que poderia tomar a entrada e armazená-la em um banco de dados-que é enviado dados em cima de um erro do aplicativo. (A base de dados poderia então ser verificada por um dev ou um script para saber se existem novos erros.)

Eu escrevi a página web em PHP e criei um mysql. banco de dados, Usuário e tabela para armazenar os dados. Eu decidi em quatro variáveis de usuário, uma identificação, e um timestamp. As variáveis possíveis (incluídas no URL ou como dados POST) são:
  • app (Nome da aplicação)
  • msg (mensagem-por exemplo, ocorreu uma excepção ...)
  • dev (desenvolvimento-por exemplo, Pat)
  • src (fonte - isto viria de uma variável pertencente à máquina em que o aplicativo estava em execução, por exemplo {[7] } ou algo assim)
  • log (um ficheiro de registo ou mensagem descritiva)

(todas as variáveis são opcionais, mas nada é relatado se nenhuma delas estiver definida - por isso, se você apenas visitar o URL do site nada é enviado para o db.)

Para enviar os dados para o URL, eu usei o Blog WebService alvo (Nota, eu tive alguns problemas com este alvo no início. Só quando olhei para a fonte é que descobri que o meu ... não podia acabar com um ... )

Apesar de tudo, não é um mau sistema para manter o controlo. aplicações externas. (Claro, a coisa educada a fazer é informar os seus usuários que você estará relatando dados possivelmente sensíveis e dar-lhes uma maneira de optar por entrar/sair.)

MySQL stuff

(o utilizador do db tem apenas privilégios INSERT nesta tabela na sua própria base de dados.)

CREATE TABLE `reports` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `ts` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `applicationName` text,
  `message` text,
  `developer` text,
  `source` text,
  `logData` longtext,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='storage place for reports from external applications'

Código do sítio web

(PHP 5.3 ou 5.2 com DOP activo , o ficheiro é index.php na /report pasta)

<?php
$app = $_REQUEST['app'];
$msg = $_REQUEST['msg'];
$dev = $_REQUEST['dev'];
$src = $_REQUEST['src'];
$log = $_REQUEST['log'];

$dbData =
    array(  ':app' => $app,
            ':msg' => $msg,
            ':dev' => $dev,
            ':src' => $src,
            ':log' => $log
    );
//print_r($dbData); // For debugging only! This could allow XSS attacks.
if(isEmpty($dbData)) die("No data provided");

try {
$db = new PDO("mysql:host=$host;dbname=reporting", "reporter", $pass, array(
    PDO::ATTR_PERSISTENT => true
));
$s = $db->prepare("INSERT INTO reporting.reports 
    (
    applicationName, 
    message, 
    developer, 
    source, 
    logData
    )
    VALUES
    (
    :app, 
    :msg, 
    :dev, 
    :src, 
    :log
    );"
    );
$s->execute($dbData);
print "Added report to database";
} catch (PDOException $e) {
// Sensitive information can be displayed if this exception isn't handled
//print "Error!: " . $e->getMessage() . "<br/>";
die("PDO error");
}

function isEmpty($array = array()) {
    foreach ($array as $element) {
        if (!empty($element)) {
            return false;
        }
    }
    return true;
}
?>

Código da aplicação (Configuração do NLog file)

<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      throwExceptions="true" internalLogToConsole="true" internalLogLevel="Warn" internalLogFile="nlog.log">
    <variable name="appTitle" value="My External App"/>
    <variable name="csvPath" value="${specialfolder:folder=Desktop:file=${appTitle} log.csv}"/>
    <variable name="developer" value="Pat"/>

    <targets async="true">
        <!--The following will keep the default number of log messages in a buffer and write out certain levels if there is an error and other levels if there is not. Messages that appeared before the error (in code) will be included, since they are buffered.-->
        <wrapper-target xsi:type="BufferingWrapper" name="smartLog">
            <wrapper-target xsi:type="PostFilteringWrapper">
                <target xsi:type="File" fileName="${csvPath}"
                archiveAboveSize="4194304" concurrentWrites="false" maxArchiveFiles="1" archiveNumbering="Sequence"
                >
                    <layout xsi:type="CsvLayout" delimiter="Comma" withHeader="false">
                        <column name="time" layout="${longdate}" />
                        <column name="level" layout="${level:upperCase=true}"/>
                        <column name="message" layout="${message}" />
                        <column name="callsite" layout="${callsite:includeSourcePath=true}" />
                        <column name="stacktrace" layout="${stacktrace:topFrames=10}" />
                        <column name="exception" layout="${exception:format=ToString}"/>
                        <!--<column name="logger" layout="${logger}"/>-->
                    </layout>
                </target>

                 <!--during normal execution only log certain messages--> 
                <defaultFilter>level >= LogLevel.Warn</defaultFilter>

                 <!--if there is at least one error, log everything from trace level--> 
                <when exists="level >= LogLevel.Error" filter="level >= LogLevel.Trace" />
            </wrapper-target>
        </wrapper-target>

        <target xsi:type="WebService" name="web"
                url="http://example.com/report" 
                methodName=""
                namespace=""
                protocol="HttpPost"
                >
            <parameter name="app" layout="${appTitle}"/>
            <parameter name="msg" layout="${message}"/>
            <parameter name="dev" layout="${developer}"/>
            <parameter name="src" layout="${environment:variable=UserName} (${windows-identity}) on ${machinename} running os ${environment:variable=OSVersion} with CLR v${environment:variable=Version}"/>
            <parameter name="log" layout="${file-contents:fileName=${csvPath}}"/>
        </target>

    </targets>

    <rules>
        <logger name="*" minlevel="Trace" writeTo="smartLog"/>
        <logger name="*" minlevel="Error" writeTo="web"/>
    </rules>
</nlog>

Nota: Pode haver alguns problemas com o tamanho do ficheiro de registo, mas ainda não descobri uma forma simples de o truncar (por exemplo, a la * nix's tail comando ).

 7
Author: Pat, 2017-05-23 10:31:18

Forma mais fácil de registar cada nível de registo com uma disposição diferente usando disposições condicionais

<variable name="VerboseLayout" value="${level:uppercase=true}: ${longdate} | ${logger}    : 
${when:when=level == LogLevel.Trace:inner=MONITOR_TRACE ${message}} 
${when:when=level == LogLevel.Debug:inner=MONITOR_DEBUG ${message}} 
${when:when=level == LogLevel.Info:inner=MONITOR_INFO ${message}} 
${when:when=level == LogLevel.Warn:inner=MONITOR_WARN ${message}} 
${when:when=level == LogLevel.Error:inner=MONITOR_ERROR ${message}} 
${when:when=level == LogLevel.Fatal:inner=MONITOR_CRITICAL ${message}} |     
${exception:format=tostring} | ${newline} ${newline}" />

Ver https://github.com/NLog/NLog/wiki/When-Filter para a sintaxe

 4
Author: Lukie, 2018-07-06 12:34:42

Registo de Silverlight

Ao usar o NLog com o Silverlight, poderá enviar a localização para o lado do servidor através do serviço web fornecido . Você também pode escrever para um arquivo local no armazenamento isolado, o que pode ser útil se o servidor web não estiver disponível. Veja aqui para mais detalhes, ou seja, use algo assim para se tornar um alvo:

namespace NLogTargets
{
    [Target("IsolatedStorageTarget")]
    public sealed class IsolatedStorageTarget : TargetWithLayout
    {
        IsolatedStorageFile _storageFile = null;
        string _fileName = "Nlog.log"; // Default. Configurable through the 'filename' attribute in nlog.config

        public IsolatedStorageTarget()
        {
        }

        ~IsolatedStorageTarget()
        {
            if (_storageFile != null)
            {
                _storageFile.Dispose();
                _storageFile = null;
            }
        }

        public string filename
        {
            set
            {
                _fileName = value; 
            }
            get
            {
                return _fileName;  
            }
         }

        protected override void Write(LogEventInfo logEvent)
        {
            try
            {
                writeToIsolatedStorage(this.Layout.Render(logEvent));
            }
            catch (Exception e)
            {
                // Not much to do about his....
            }
        }

        public void writeToIsolatedStorage(string msg)
        {
            if (_storageFile == null)
                _storageFile = IsolatedStorageFile.GetUserStoreForApplication();
            using (IsolatedStorageFile isolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
            {
                // The isolated storage is limited in size. So, when approaching the limit
                // simply purge the log file. (Yeah yeah, the file should be circular, I know...)
                if (_storageFile.AvailableFreeSpace < msg.Length * 100)
                {
                    using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(_fileName, FileMode.Truncate, FileAccess.Write, isolatedStorage))
                    { }
                }
                // Write to isolated storage
                using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(_fileName, FileMode.Append, FileAccess.Write, isolatedStorage))
                {
                    using (TextWriter writer = new StreamWriter(stream))
                    {
                        writer.WriteLine(msg);
                    }
                }
            }
        }
    } 
}
 3
Author: BaBu, 2017-05-23 11:47:36