การกำหนดค่า NLog ที่มีประโยชน์มากที่สุด [ปิด]


348

การกำหนดค่าที่ดีที่สุดหรือมีประโยชน์ที่สุดสำหรับการบันทึกด้วย NLog คืออะไร (สิ่งเหล่านี้สามารถเรียบง่ายหรือซับซ้อนได้ตราบใดที่มีประโยชน์)

ฉันกำลังคิดถึงตัวอย่างเช่นการกลิ้งไฟล์บันทึกโดยอัตโนมัติในขนาดที่กำหนดเปลี่ยนรูปแบบ (ข้อความบันทึก) ไม่ว่าจะมีข้อยกเว้นหรือไม่การเพิ่มระดับของบันทึกเมื่อเกิดข้อผิดพลาด ฯลฯ

นี่คือลิงค์บางส่วน:


3
ต่อไปนี้เป็นเคล็ดลับการปรับแต่งประสิทธิภาพตามการทดสอบ: deep-depth.blogspot.com/2014/01/…
Neil

คำตอบ:


391

บางส่วนตกอยู่ในหมวดหมู่ของเคล็ดลับ NLog ทั่วไป (หรือการบันทึก) แทนที่จะเป็นคำแนะนำการกำหนดค่าอย่างเคร่งครัด

นี่คือลิงค์บันทึกทั่วไปจากที่นี่ที่ SO (คุณอาจเคยเห็นลิงก์เหล่านี้บางส่วนหรือทั้งหมดแล้ว):

log4net กับ Nlog

การบันทึกแนวทางปฏิบัติที่ดีที่สุด

สิ่งที่เป็นจุดสำคัญของซุ้มทำไม้?

ทำไมคนตัดไม้แนะนำให้ใช้คนตัดไม้ต่อคลาส?

Logger logger = LogManager.GetCurrentClassLogger()ใช้รูปแบบทั่วไปของการตั้งชื่อคนตัดไม้ของคุณขึ้นอยู่กับการเรียน สิ่งนี้จะช่วยให้คุณมีความละเอียดระดับสูงในตัวบันทึกและให้ความยืดหยุ่นอย่างมากในการกำหนดค่าตัวบันทึก (ควบคุมทั่วโลกตามเนมสเปซตามชื่อตัวบันทึกเฉพาะ ฯลฯ )

ใช้ตัวบันทึกที่ไม่ใช่ชื่อคลาสตามความเหมาะสม บางทีคุณอาจมีฟังก์ชั่นเดียวที่คุณต้องการควบคุมการบันทึกแยกต่างหาก บางทีคุณอาจมีข้อกังวลเกี่ยวกับการบันทึกแบบตัดต่อกัน (การบันทึกประสิทธิภาพ)

หากคุณไม่ได้ใช้การบันทึกแบบใช้ชื่อคลาสให้พิจารณาตั้งชื่อตัวบันทึกของคุณในโครงสร้างแบบลำดับชั้นบางประเภท (อาจตามพื้นที่การใช้งาน) เพื่อให้คุณสามารถรักษาความยืดหยุ่นในการกำหนดค่าได้มากขึ้น ตัวอย่างเช่นคุณอาจมีพื้นที่ใช้งาน "ฐานข้อมูล" การวิเคราะห์ "FA" และ "ui" FA แต่ละเหล่านี้อาจมีพื้นที่ย่อย ดังนั้นคุณอาจขอคนตัดไม้แบบนี้:

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");

และอื่น ๆ ด้วยตัวบันทึกลำดับชั้นคุณสามารถกำหนดค่าการบันทึกทั่วโลก ("*" หรือ root logger) โดย FA (ฐานข้อมูลการวิเคราะห์ UI) หรือตามพื้นที่ย่อย (Database.Connect ฯลฯ )

ตัวบันทึกมีตัวเลือกการกำหนดค่ามากมาย:

<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" /> 

ดูวิธีใช้NLogสำหรับข้อมูลเพิ่มเติมเกี่ยวกับความหมายของตัวเลือกแต่ละตัว อาจเป็นสิ่งที่น่าสังเกตมากที่สุดของที่นี่คือความสามารถในการใช้กฎตัวแทนคนตัดไม้แนวคิดที่ว่ากฎคนตัดไม้หลายคนสามารถ "ดำเนินการ" สำหรับคำสั่งการบันทึกเดียวและกฎการบันทึกสามารถทำเครื่องหมายว่า "สุดท้าย" ดังนั้นกฎต่อมา รับงบการบันทึก

ใช้ GlobalDiagnosticContext, MappedDiagnosticContext และ NestedDiagnosticContext เพื่อเพิ่มบริบทเพิ่มเติมให้กับเอาต์พุตของคุณ

ใช้ "ตัวแปร" ในไฟล์กำหนดค่าของคุณเพื่อทำให้ง่ายขึ้น ตัวอย่างเช่นคุณอาจกำหนดตัวแปรสำหรับโครงร่างของคุณแล้วอ้างอิงตัวแปรในการกำหนดค่าเป้าหมายแทนที่จะระบุเค้าโครงโดยตรง

  <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>

หรือคุณสามารถสร้างชุดคุณสมบัติ "กำหนดเอง" เพื่อเพิ่มลงในเค้าโครง

  <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}"/>

หรือคุณสามารถทำสิ่งต่าง ๆ เช่นสร้างตัวเรนเดอร์เค้าโครง "วัน" หรือ "เดือน" อย่างเคร่งครัดผ่านการกำหนดค่า:

  <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>

คุณสามารถใช้เลย์เอาต์การแสดงเพื่อกำหนดชื่อไฟล์ของคุณ:

  <variable name="day" value="${date:format=dddd}"/>
  <targets>
    <target name="file" xsi:type="File" layout="${verbose}" fileName="${basedir}/${day}.log" />
  </targets>

หากคุณหมุนไฟล์ทุกวันไฟล์แต่ละไฟล์อาจมีชื่อว่า "Monday.log", "Tuesday.log" ฯลฯ

อย่ากลัวที่จะเขียนเค้าร่างของคุณเอง มันเป็นเรื่องง่ายและช่วยให้คุณสามารถเพิ่มข้อมูลบริบทของคุณเองไปยังไฟล์บันทึกผ่านการกำหนดค่า ตัวอย่างเช่นนี่คือตัวแสดงโครงร่าง (ตาม NLog 1.x ไม่ใช่ 2.0) ที่สามารถเพิ่ม Trace.CorrelationManager.ActivityId ลงในบันทึก:

  [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;
    }
  }

บอก NLog ว่าส่วนขยาย NLog ของคุณอยู่ที่ไหน (แอสเซมบลีใด) เช่นนี้

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

ใช้ตัวสร้างเค้าโครงที่กำหนดเองดังนี้:

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

ใช้เป้าหมาย async:

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

และ wrappers เป้าหมายเริ่มต้น:

<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>

ที่เหมาะสม. ดูเอกสาร NLog สำหรับข้อมูลเพิ่มเติมเกี่ยวกับเอกสารเหล่านั้น

บอก NLog ให้ดูและโหลดการกำหนดค่าใหม่โดยอัตโนมัติหากมีการเปลี่ยนแปลง:

<nlog autoReload="true" /> 

มีตัวเลือกการกำหนดค่าหลายอย่างที่จะช่วยแก้ไขปัญหา NLog

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

ดูวิธีใช้ NLog สำหรับข้อมูลเพิ่มเติม

NLog 2.0 เพิ่มการห่อหุ้ม LayoutRenderer ที่ช่วยให้การประมวลผลเพิ่มเติมที่จะดำเนินการในการส่งออกของการแสดงผลเค้าโครง (เช่นการตัดช่องว่างการตัดตัวพิมพ์ใหญ่ตัวพิมพ์เล็ก ฯลฯ )

อย่ากลัวที่จะปิดตัวบันทึกถ้าคุณต้องการป้องกันรหัสของคุณจากการพึ่งพาอย่างหนักใน NLog แต่ห่ออย่างถูกต้อง มีตัวอย่างวิธีห่อในพื้นที่เก็บข้อมูล github ของ NLog เหตุผลอื่นในการตัดคำอาจเป็นเพราะคุณต้องการเพิ่มข้อมูลบริบทเฉพาะลงในแต่ละข้อความที่บันทึกไว้โดยอัตโนมัติ (โดยใส่ลงใน LogEventInfo.Context)

มีข้อดีข้อเสียของการตัด (หรือสรุป) NLog (หรือกรอบงานการบันทึกอื่น ๆ สำหรับเรื่องนั้น) ด้วยความพยายามเพียงเล็กน้อยคุณสามารถค้นหาข้อมูลมากมายได้ที่นี่เพื่อนำเสนอทั้งสองด้าน

หากคุณกำลังพิจารณาตัดพิจารณาใช้Common.Logging มันทำงานได้ค่อนข้างดีและช่วยให้คุณสามารถสลับไปยังเฟรมเวิร์กการบันทึกอื่นได้อย่างง่ายดายหากคุณต้องการ นอกจากนี้หากคุณกำลังพิจารณาการห่อคิดเกี่ยวกับวิธีที่คุณจะจัดการกับวัตถุบริบท (GDC, MDC, NDC) Common.Logging ไม่สนับสนุน abstraction สำหรับพวกเขาในปัจจุบัน แต่คาดว่าจะเพิ่มความสามารถในคิว


3
คำตอบที่ดี มีเพียงสิ่งเดียวที่ควรเพิ่ม $ {machine} ควรเป็น $ {machinename} ดูgithub.com/nlog/NLog/wiki/Layout-Renderers
เหลียง

2
ฉันคดเคี้ยว Common.Logging และเพิ่มนามธรรมหายไปดูโครงการ GitHubหรือNuGet
Danny Varod

ฉันไม่พบสิ่งใดที่ให้ข้อมูลเกี่ยวกับ nlog ในเอกสารของตัวเองบางทีฉันอาจดูตัวอย่าง github ในทางที่ผิด? ใครจะรู้.
JARRRRG

วิธีการใช้ renderer ที่กำหนดเองนั้นกับ API (ไม่มีไฟล์ปรับแต่ง) นี่คือสิ่งที่ฉันพยายามทำ
InteXX

ตกลงเข้าใจแล้ว NewLineรูปแบบสำเร็จงาน นี่คือสิ่งที่ฉันมาด้วย แน่นอนว่าง่ายกว่าที่ฉันคิดไว้มาก
InteXX

65

การรักษาข้อยกเว้นแตกต่างกัน

เรามักต้องการรับข้อมูลเพิ่มเติมเมื่อมีข้อยกเว้น การกำหนดค่าต่อไปนี้มีสองเป้าหมายคือไฟล์และคอนโซลซึ่งกรองว่ามีข้อมูลข้อยกเว้นหรือไม่ (แก้ไข: Jarek โพสต์เกี่ยวกับวิธีการใหม่ในการทำเช่นนี้ใน vNext )

กุญแจสำคัญคือการมีเป้าหมายห่อหุ้มด้วย 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>

1
มันยอดเยี่ยมมากกับเป้าหมายแยกต่างหากและ FilteringWrapper เพื่อจัดรูปแบบข้อยกเว้น ฉันเพิ่งตอบคำถามจากคนที่ต้องการรวม {render} layout renderer ในผลลัพธ์ของเขา แต่เขาไม่ต้องการรับ () ที่เห็นได้ชัดว่ามีการบันทึกหากไม่มีข้อยกเว้น เทคนิคนี้อาจใช้ได้ดีสำหรับเขา
wageoghe

+1 ดีมาก ฉันเคยทำบุ๊กมาร์กนี้มานานแล้วและได้รับการอ้างอิงถึง "ความคิดเห็นของ Pat" จากคำถาม SO อื่นเกี่ยวกับเลย์เอาต์ที่มีเงื่อนไข
eduncan911

1
หากมีการบันทึกข้อยกเว้นมันจะถูกบันทึกสองครั้ง (ส่วน VerboseLayout)
Tien Do

2
ฉันเพิ่งลองในวันพรุ่งนี้ในโครงการของฉันเนื่องจากคุณตั้งค่ากฎ minlevel = "เตือน" เป็น "file, fileAsException" บันทึกทั้งหมดจะถูกบันทึกไว้ก่อนด้วยเป้าหมายไฟล์ (ไม่มีตัวกรอง) และหากมีข้อยกเว้น (กรองตาม เงื่อนไข) มันจะถูกบันทึกด้วย fileAsException
Tien Do

3
@ Tiendq โอ้ฉันเห็นแล้ว ที่เหมาะสมแม้ว่าข้อยกเว้นตัวเอง (ในรายละเอียดทั้งหมด) จะถูกบันทึกเพียงครั้งเดียว (แต่ข้อความจะถูกบันทึกสองครั้ง) คุณอาจจะสามารถแก้ไขปัญหาที่โดยการเพิ่มcondition="length('${exception}')=0(หรือบางทีมันอาจจะ==) target name="file"ไป
Pat

60

เห็นได้ชัดว่าตอนนี้คุณสามารถใช้NLog กับ Growl สำหรับ 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 กับ Growl สำหรับ Windows ข้อความการติดตาม NLog ด้วย Growl สำหรับ Windows ข้อความดีบัก NLog ด้วย Growl สำหรับ Windows ข้อความแสดงข้อมูล NLog กับ Growl สำหรับ Windows NLog ข้อความเตือนด้วย Growl สำหรับ Windows ข้อความแสดงข้อผิดพลาด NLog กับ Growl สำหรับ Windows ข้อความแสดงข้อผิดพลาดร้ายแรงกับ NLL กับ Growl สำหรับ Windows


คุณช่วยบอกฉันได้ไหมว่าจะต้องทำอย่างไรกับการเชื่อมต่อแบบ remort สิ่งที่เหมาะกับฉันสำหรับ localhost แต่เมื่อฉันได้ให้ที่อยู่ ip ในโฮสต์มันไม่ทำงาน !!
Neel

@ ไม่เช่นนั้นคุณควรตรวจสอบการตั้งค่า "ความปลอดภัย" ในคำนำในคอมพิวเตอร์เป้าหมาย คุณต้องเปิดใช้งานการแจ้งเตือน "LAN" อย่างชัดเจนและคุณอาจต้องการตั้งค่ารหัสผ่าน (ซึ่งคุณจะต้องเพิ่มลงในเป้าหมาย NLog ของคุณ) แต่ฉันไม่ชอบที่การแจ้งเตือนระยะไกลปรากฏขึ้นใน Growl ด้วย "Origin" ของ "Local Machine"; ฉันต้องเพิ่มโฮสต์ในรายการบันทึกเพื่อทราบว่าการแจ้งเตือนเกิดขึ้นที่ไหน
Kenny Evitt

ฉันสามารถรับการแจ้งเตือนให้ทำงานบนเครื่องท้องถิ่นของฉัน แต่ไม่ใช่จากระยะไกล การตั้งค่าความปลอดภัยของฉันไม่มีรหัสผ่านบนคำรามดังนั้นสิ่งที่ฉันเพิ่มคือ IP และพอร์ต แต่ไม่มีอะไรได้รับการส่ง
Jack Reilly

1
โครงการนี้ตายแล้ว 100%
พัฒนา

28

กำหนดค่า NLog ผ่าน XML แต่โดยทางโปรแกรม

อะไร? คุณรู้หรือไม่ว่าคุณสามารถระบุ NLog XML โดยตรงไปยัง NLog จากแอปของคุณซึ่งไม่ใช่ NLog ที่อ่านจากไฟล์ปรับแต่ง คุณทำได้ สมมติว่าคุณมีแอพที่กระจายและคุณต้องการใช้การกำหนดค่าเดียวกันทุกที่ คุณสามารถเก็บไฟล์ปรับแต่งในแต่ละตำแหน่งและรักษาแยกต่างหากคุณสามารถเก็บไว้ในตำแหน่งกลางและผลักมันออกไปยังตำแหน่งดาวเทียมหรือคุณอาจทำสิ่งอื่นมากมาย หรือคุณสามารถเก็บ XML ของคุณในฐานข้อมูลรับตอนเริ่มต้นแอพและกำหนดค่า NLog โดยตรงกับ XML นั้น (อาจตรวจสอบย้อนกลับเป็นระยะเพื่อดูว่ามีการเปลี่ยนแปลง)

  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

ฉันไม่แน่ใจว่านี่จะแข็งแกร่งแค่ไหน แต่ตัวอย่างนี้ให้จุดเริ่มต้นที่มีประโยชน์สำหรับคนที่อาจต้องการลองกำหนดค่าเช่นนี้


มันทำงานได้ดีมาก ... ยกเว้นเมื่อใช้สิ่งนี้จะไม่สามารถกำหนดค่าระบบบันทึกอีกครั้งแบบไดนามิก โดยเฉพาะอย่างยิ่งถ้าคุณเชื่อมโยงไปยังไฟล์ภายนอก (รวม)
Newtopian

2
งานนี้แม้ว่าฉันจะต้องเขียน XML "ดี" โดยรวมถึง:<?xml version='1.0' encoding='utf-8' ?><nlog xmlns='http://nlog-project.org/schemas/NLog.xsd' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>
Gady

1
นี่คือ segway ที่ดีในการกำหนดค่าส่วนกลาง ผู้อ่านในอนาคต, ฮาร์ดโค้ดแบบ XML ในตัวอย่างนี้สำหรับการสาธิตเท่านั้น (IMHO) การอ่านจากฐานข้อมูลหรือไฟล์จากส่วนกลางอาจเป็นการใช้งานจริง
granadaCoder

@wageoghe; ทำไมฉันถึงได้รับข้อผิดพลาด (ไม่มีคนตัดไม้) ฉันเพิ่งคัดลอกและวางรหัส
Bsflasher

22

การบันทึกระดับต่าง ๆ ขึ้นอยู่กับว่ามีข้อผิดพลาดหรือไม่

ตัวอย่างนี้ช่วยให้คุณได้รับข้อมูลเพิ่มเติมเมื่อมีข้อผิดพลาดในรหัสของคุณ โดยทั่วไปจะบัฟเฟอร์ข้อความและส่งออกเฉพาะที่ระดับการบันทึกที่แน่นอน (เช่นเตือน) เว้นแต่ว่ามีเงื่อนไขบางประการ (เช่นมีข้อผิดพลาดดังนั้นระดับการบันทึกคือ> = ข้อผิดพลาด) จากนั้นจะส่งข้อมูลเพิ่มเติม (เช่น ข้อความทั้งหมดจากระดับการบันทึก> = ติดตาม) เนื่องจากข้อความถูกบัฟเฟอร์สิ่งนี้จะช่วยให้คุณรวบรวมข้อมูลการติดตามเกี่ยวกับสิ่งที่เกิดขึ้นก่อนที่จะบันทึกข้อผิดพลาดหรือ ErrorException ซึ่งมีประโยชน์มาก!

ผมดัดแปลงมานี้จากตัวอย่างในรหัสที่มา ฉันถูกขว้างในตอนแรกเพราะฉันออกจากAspNetBufferingWrapper(เพราะของฉันไม่ใช่แอป ASP) - ปรากฎว่าPostFilteringWrapperต้องการเป้าหมายที่บัฟเฟอร์บางอย่าง โปรดทราบว่าtarget-refองค์ประกอบที่ใช้ในตัวอย่างที่ลิงก์ข้างต้นไม่สามารถใช้ใน NLog 1.0 (ฉันใช้ 1.0 Refresh สำหรับแอป. NET 4.0) มีความจำเป็นต้องใส่เป้าหมายของคุณลงในบล็อกของตัวคลุม โปรดทราบว่าไวยากรณ์ตรรกะ (เช่นสัญลักษณ์มากกว่าหรือน้อยกว่า <และ>) จะต้องใช้สัญลักษณ์ไม่ใช่ XML escapes สำหรับสัญลักษณ์เหล่านั้น (เช่น&gt;และ&lt;) มิฉะนั้น NLog จะผิดพลาด

app.config:

<?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>

ใน NLog บางรุ่น (สำหรับขาวดำและฉันคิดว่า 2.0) นี่เป็นสาเหตุของ StackOverflowException แต่ไม่ใช่ในรุ่นอื่น (NLog 1 refresh)
Pat

เกี่ยวกับการโอเวอร์โฟลว์ - ดูเหมือนว่าจะเกิดจากเฉพาะเลย์เอาต์ที่เป็นประเภท CSV - หากฉันทำเลย์เอาต์ปกติไม่มีปัญหา
Pat

fileAsCsv target-ref คืออะไร? ฉันพยายามที่จะรับตัวอย่างนี้เพื่อทำงานกับ NLog v2.0.0.2000 แต่จนถึงขณะนี้ล้มเหลว
Peter Mounce

@PeterMounce fileAsCsvเป้าหมายการอ้างอิงเป็นเพียงสิ่งประดิษฐ์จากการทดสอบของฉัน ฉันเชื่อว่า NLog 2 มี / มีปัญหากับ CsvLayouts ที่ NLog 1 / Refresh ไม่มี
Pat

22

ฉันให้คำตอบที่น่าสนใจพอสมควรสำหรับคำถามนี้:

Nlog - การสร้างส่วนหัวสำหรับไฟล์บันทึก

การเพิ่มส่วนหัว:

คำถามอยากรู้วิธีเพิ่มส่วนหัวในล็อกไฟล์ การใช้รายการตั้งค่าเช่นนี้ช่วยให้คุณสามารถกำหนดรูปแบบส่วนหัวแยกจากรูปแบบของรายการบันทึกที่เหลือ ใช้ตัวบันทึกคนเดียวซึ่งอาจเรียกว่า "headerlogger" เพื่อบันทึกข้อความเดียวที่จุดเริ่มต้นของแอปพลิเคชันและคุณจะได้รับส่วนหัวของคุณ:

กำหนดส่วนหัวและโครงร่างไฟล์:

  <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}" />

กำหนดเป้าหมายโดยใช้เลย์เอาต์:

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

กำหนด loggers:

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

เขียนส่วนหัวซึ่งอาจเร็วในโปรแกรม:

  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");

นี่เป็นเพียงส่วนใหญ่ของแนวคิด "การจัดการข้อยกเว้นต่างกัน" รุ่นอื่น

บันทึกแต่ละระดับการบันทึกด้วยเค้าโครงที่แตกต่างกัน

โปสเตอร์ต้องการทราบวิธีการเปลี่ยนรูปแบบต่อระดับการบันทึก ไม่ชัดเจนสำหรับฉันว่าเป้าหมายสุดท้ายคืออะไร (และสามารถทำได้ในลักษณะ "ดีกว่า") แต่ฉันสามารถให้การกำหนดค่าที่ทำในสิ่งที่เขาถาม:

  <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> 

อีกครั้งคล้ายกับการปฏิบัติกับข้อยกเว้นต่างกันมาก


1
เย็น! ฉันไม่เคยเห็นGlobalDiagnosticsContextมาก่อน
Pat

10

เข้าสู่ระบบ Twitter

อ้างอิงจากโพสต์นี้เกี่ยวกับ log4net Twitter Appenderฉันคิดว่าฉันจะลองเขียน NLog Twitter Target (ใช้การรีเฟรช NLog 1.0 ไม่ใช่ 2.0) อนึ่งจนถึงตอนนี้ฉันยังไม่สามารถรับทวีตเพื่อโพสต์ได้สำเร็จ ฉันไม่รู้ว่ารหัสผิด, Twitter, การเชื่อมต่ออินเทอร์เน็ต / ไฟร์วอลล์ของ บริษัท เราหรือไม่ ฉันกำลังโพสต์รหัสที่นี่ในกรณีที่มีคนสนใจทดลองใช้ โปรดทราบว่ามีวิธี "โพสต์" ที่แตกต่างกันสามวิธี อันแรกที่ฉันลองคือ PostMessageToTwitter PostMessageToTwitter เป็นหลักเหมือนกับ PostLoggingEvent ในโพสต์ดั้งเดิม ถ้าฉันใช้ที่ฉันได้รับข้อยกเว้น 401 PostMessageBasic ได้รับข้อยกเว้นเดียวกัน PostMessage ทำงานโดยไม่มีข้อผิดพลาด แต่ข้อความยังไม่สามารถใช้งานได้ถึง Twitter PostMessage และ PostMessageBasic อิงตามตัวอย่างที่ฉันพบที่นี่ใน SO

FYI - ตอนนี้ฉันเพิ่งพบความคิดเห็นโดย @Jason Diller สำหรับคำตอบในโพสต์นี้ที่ระบุว่า Twitter กำลังจะปิดการตรวจสอบสิทธิ์ขั้นพื้นฐาน "เดือนหน้า" นี่คือย้อนกลับไปในเดือนพฤษภาคม 2010 และตอนนี้คือเดือนธันวาคม 2010 ดังนั้นฉันเดาว่าอาจเป็นสาเหตุที่ทำให้สิ่งนี้ไม่ทำงาน

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) + "...";
    }
  }
}

กำหนดค่าเช่นนี้:

บอก NLog ชุดประกอบที่มีเป้าหมาย:

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

กำหนดค่าเป้าหมาย:

<targets>
    <target name="twitter" type="TwitterTarget" TwitterUserName="yourtwittername" TwitterPassword="yourtwitterpassword" layout="${longdate} ${logger} ${level} ${message}" />
</targets>

หากใครบางคนลองทำสิ่งนี้และประสบความสำเร็จลองโพสต์สิ่งที่คุณค้นพบ


Twitter ใช้ OAuth - .NET มีผู้ให้บริการในdotnetopenauth.net
Pat

8

วิธีที่ง่ายกว่าในการบันทึกแต่ละระดับการบันทึกด้วยเค้าโครงที่แตกต่างกันโดยใช้การจัดหน้าแบบมีเงื่อนไข

<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}" />

ดูhttps://github.com/NLog/NLog/wiki/When-Filterเพื่อหาไวยากรณ์


7

การรายงานไปยังเว็บไซต์ / ฐานข้อมูลภายนอก

ฉันต้องการวิธีในการรายงานข้อผิดพลาดอย่างง่าย ๆ และโดยอัตโนมัติ (เนื่องจากผู้ใช้มักไม่ทำ) จากแอปพลิเคชันของเรา ทางออกที่ง่ายที่สุดที่ฉันสามารถทำได้คือ URL สาธารณะ - หน้าเว็บที่สามารถป้อนข้อมูลและจัดเก็บไว้ในฐานข้อมูล - ซึ่งส่งข้อมูลเมื่อข้อผิดพลาดของแอปพลิเคชัน (จากนั้นสามารถตรวจสอบฐานข้อมูลโดย dev หรือสคริปต์เพื่อทราบว่ามีข้อผิดพลาดใหม่หรือไม่)

ฉันเขียนเว็บเพจใน PHP และสร้างฐานข้อมูล mysql ผู้ใช้และตารางเพื่อจัดเก็บข้อมูล ฉันตัดสินใจเลือกตัวแปรผู้ใช้สี่ตัว id และ timestamp ตัวแปรที่เป็นไปได้ (รวมอยู่ใน URL หรือเป็นข้อมูล POST) คือ:

  • app (ชื่อแอปพลิเคชัน)
  • msg (ข้อความ - เช่นมีข้อยกเว้นเกิดขึ้น ... )
  • dev (ผู้พัฒนา - เช่น Pat)
  • src(แหล่งที่มา - สิ่งนี้จะมาจากตัวแปรที่เกี่ยวข้องกับเครื่องที่แอพกำลังทำงานเช่นEnvironment.MachineNameหรือบางอย่าง)
  • log (ไฟล์บันทึกหรือข้อความ verbose)

(ตัวแปรทั้งหมดเป็นทางเลือก แต่จะไม่มีการรายงานหากไม่มีการตั้งค่าตัวแปรเหล่านั้น - ดังนั้นหากคุณเพิ่งเยี่ยมชมเว็บไซต์ URL จะไม่มีสิ่งใดถูกส่งไปยังฐานข้อมูล)

ที่จะส่งข้อมูลไปยัง URL ที่ผมใช้ NLog ของเป้าหมายWebService (หมายเหตุฉันมีปัญหาเล็กน้อยกับเป้าหมายนี้ในตอนแรกมันไม่ได้จนกว่าฉันจะดูที่มาที่ฉันคิดว่าฉันurlไม่สามารถจบด้วย/)

สรุปแล้วมันไม่ใช่ระบบที่ไม่ดีเลยสำหรับการเก็บแท็บในแอพภายนอก (แน่นอนสิ่งที่ต้องทำคือการแจ้งให้ผู้ใช้ของคุณทราบว่าคุณจะต้องรายงานข้อมูลที่ละเอียดอ่อนและเพื่อให้พวกเขามีทางเลือกในการเข้า / ออก)

สิ่ง MySQL

(ผู้ใช้ db มีINSERTสิทธิ์เฉพาะบนตารางนี้เดียวในฐานข้อมูลของตนเอง)

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'

รหัสเว็บไซต์

(PHP 5.3 หรือ 5.2 พร้อมเปิดใช้งานPDO ไฟล์อยู่ในโฟลเดอร์)index.php/report

<?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;
}
?>

รหัสแอป (ไฟล์กำหนดค่า NLog)

<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>

หมายเหตุ: อาจมีปัญหาบางอย่างเกี่ยวกับขนาดของไฟล์บันทึก แต่ฉันไม่ได้คิดวิธีง่ายๆในการตัด (เช่นtailคำสั่ง la * nix )


สิ่งนี้ใช้ได้กับโครงการหนึ่ง แต่ในโครงการอื่นฉันมีปัญหากับurl: InnerException: System.InvalidCastException Message = การส่งไม่ถูกต้องจาก 'System.String' เป็น 'System.Uri' Source = mscorlib StackTrace: ที่ System.Convert.DefaultToType (ค่า IConvertible, ประเภท targetType, ผู้ให้บริการ IFormatProvider) ที่ System.String.System.IConvertible.ToType (ประเภท Type, ผู้ให้บริการ IFormatProvider) , ผู้ให้บริการ IFormatProvider)
Pat

ตัวเลือกอื่นหากคุณต้องการให้สามารถตรวจสอบบันทึกและได้รับแจ้งในกรณีที่เกิดข้อผิดพลาดจะเป็นเป้าหมายของ Twitter ดูลิงค์นี้สำหรับ Twitter Appender ที่เขียนขึ้นสำหรับ log4net: twitterappender.codeplex.com การโพสต์บล็อกดั้งเดิมที่กล่าวถึงเรื่องนี้อยู่ที่นี่: caseywatson.com/2009/07/07/log4net-twitter-awesome มันค่อนข้างง่ายที่จะเขียนสิ่งที่คล้ายกันสำหรับ NLog
wageoghe

ฉันหลงกลด้วยการเขียน NLog Twitter เป้าหมาย แต่ไม่ประสบความสำเร็จจริง ๆ แล้วการโพสต์ทวีต ฉันโพสต์รหัสเป็นคำตอบ รู้สึกอิสระที่จะลองถ้าคุณต้องการ
wageoghe

4

บันทึกจาก Silverlight

เมื่อใช้ NLog กับ Silverlight คุณสามารถส่งการติดตามไปยังฝั่งเซิร์ฟเวอร์ผ่านบริการบนเว็บที่ให้ไว้ นอกจากนี้คุณยังสามารถเขียนไปยังไฟล์ในตัวเครื่องใน Isolated Storage ซึ่งมีประโยชน์หากเว็บเซิร์ฟเวอร์ไม่พร้อมใช้งาน ดูรายละเอียดที่นี่เช่นใช้สิ่งนี้เพื่อทำให้ตัวเองเป็นเป้าหมาย:

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);
                    }
                }
            }
        }
    } 
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.