整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          C#中編寫系統操作日志的實踐

          C#中編寫系統操作日志的實踐

          統操作日志在軟件開發和運維過程中起著至關重要的作用。通過記錄系統在運行時的關鍵操作和事件,操作日志能幫助開發者監控系統狀態、診斷問題、追蹤錯誤,并為系統的安全性和穩定性提供保障。在C#中,我們可以利用多種方法來編寫系統操作日志,本文將詳細介紹這一過程,并提供實用的示例代碼。

          一、系統操作日志的重要性

          系統操作日志記錄了軟件或系統在運行時的各種活動,包括但不限于用戶登錄、數據修改、異常發生等關鍵事件。這些日志對于后續的故障排查、系統優化、安全審計等方面都具有極高的價值。通過查看和分析日志,開發人員可以快速定位并解決問題,從而提高系統的可靠性和性能。

          二、在C#中編寫系統操作日志

          在C#中,我們可以使用內置的System.Diagnostics命名空間中的TraceDebug類來記錄日志,也可以使用第三方的日志庫,如NLog、log4net等。以下是一個使用Trace類的基本示例:

          1. 引入命名空間:首先,你需要在代碼文件的頂部引入System.Diagnostics命名空間。
          using System.Diagnostics;
          1. 配置監聽器:在應用程序的配置文件(如App.config或Web.config)中,你可以配置Trace類的監聽器,以決定將日志信息輸出到哪里,比如文件、控制臺或Windows事件查看器等。

          2. 編寫日志:在你的代碼中,你可以使用Trace.WriteLine方法來記錄日志。

          Trace.WriteLine("This is a trace message.");
          1. 條件編譯:你還可以使用條件編譯指令來確保僅在調試期間記錄日志。
          #if DEBUG
          Trace.WriteLine("Debug message.");
          #endif
          1. 使用第三方庫:對于更復雜的日志需求,如日志級別控制、日志文件分割、異步記錄等,你可能需要使用像NLog或log4net這樣的第三方庫。這些庫提供了更豐富的功能和更靈活的配置選項。

          三、示例代碼

          以下是一個簡單的示例,展示了如何在C#中使用Trace類記錄系統操作日志:

          using System;
          using System.Diagnostics;

          namespace LoggingExample
          {
          class Program
          {
          static void Main(string[] args)
          {
          // 配置Trace監聽器(通常在配置文件中完成)
          Trace.Listeners.Add(new TextWriterTraceListener("log.txt"));
          Trace.AutoFlush=true;

          // 記錄操作日志
          Trace.WriteLine("System started at " + DateTime.Now);

          // 模擬一些系統操作
          PerformSomeOperation();

          // 記錄操作完成日志
          Trace.WriteLine("Operation completed successfully.");
          }

          static void PerformSomeOperation()
          {
          Trace.WriteLine("Performing some operation...");
          // 執行具體操作的代碼...
          }
          }
          }

          在這個示例中,我們創建了一個TextWriterTraceListener來將日志信息寫入名為"log.txt"的文件中。然后,在程序的關鍵點,我們使用Trace.WriteLine方法來記錄日志。

          四、日志編寫的最佳實踐

          1. 清晰性:確保日志信息清晰明了,能夠準確反映系統狀態和操作結果。
          2. 簡潔性:避免在日志中記錄過多冗余信息,保持日志的簡潔性。
          3. 可維護性:使用一致的日志格式和命名規范,便于后續日志的分析和維護。
          4. 安全性:確保日志文件的訪問權限得到適當控制,防止敏感信息泄露。
          5. 性能考慮:對于高性能要求的應用,需要選擇合適的日志級別和異步日志記錄方式,以減少對系統性能的影響。


          Python 項目中,使用打印語句和堆棧跟蹤很容易跟蹤代碼進度和調試。但是,日志記錄提供了使用時間戳、文件名、代碼行數等進行跟蹤和調試的附加功能,區分不同類型的打印語句,甚至可以選擇將打印語句保存到日志文件或其他位置,而不是只能在控制臺或命令行上查看。

          本文將介紹日志記錄的組件,如何在文件中執行日志記錄,以及如何使用配置以可重用和可擴展的方式跨多個文件執行日志記錄。

          目錄

          • 日志記錄的組件:文件、級別、格式
          • 文件中的基本日志記錄
          • 日志記錄的高級組件:記錄器、處理程序、過濾器、格式化程序
          • 帶有配置文件的高級日志記錄
          • 常見問題:日志配置覆蓋、繼承

          日志記錄的組件

          在深入研究代碼實現之前,一些組件對于有效使用日志記錄是不可或缺的。

          日志文件——在哪里記錄?

          建議將日志保存到日志文件中,而不是在控制臺或命令行上查看它們,因為一旦控制臺或終端關閉,信息就會消失。我們可以指定要存儲日志的項目的相對路徑。

          您還可以定義保存模式。默認情況下,日志以追加模式保存,但可以更改為寫入模式以覆蓋以前的日志。

          日志級別——何時記錄?

          根據所跟蹤事件的任務和嚴重性,有 5 種日志記錄級別。按照嚴重程度遞增的順序,

          • DEBUG:記錄詳細信息,用于診斷問題,即故障調查
          • INFO:記錄詳細信息,在程序正常運行時使用,即狀態監控
          • WARN:記錄未來的意外事件或潛在問題,當代碼盡管發生意外事件仍能按預期工作時使用
          • ERROR:記錄嚴重問題,當代碼無法執行某些功能時使用
          • CRITICAL:記錄嚴重錯誤,在代碼無法繼續運行時使用

          有疑問時,我總是INFO在正常操作時使用水平儀,WARN或者ERROR在遇到小問題和主要問題時使用水平儀。

          默認情況下,日志級別為WARN,表示低于該級別的日志級別,即DEBUGINFO,除非更改默認日志級別,否則不會記錄。

          日志格式——記錄什么?

          可以設置日志格式,并將此格式應用于所有日志條目——這意味著您不必手動將相同的格式標準化到每個日志調用!默認情況下,日志條目遵循格式levelname:name:message,例如,DEBUG:root:This is a log entry但可以自定義以包含更多信息,

          • asctime:日志時間,具有默認格式%Y-%m-%d %H:%M:%S,%f,但可以按照 Python 日期時間模塊格式代碼進行更改
          • levelname:日志級別,即DEBUG,,INFO
          • name:記錄器的名稱,默認為root
          • filename: 包含日志調用的文件名,即file.py
          • module:文件名的名稱部分,即file
          • funcName:包含日志調用的函數名稱,即function_name
          • lineno: 發出日志調用的文件的行號
          • message: 日志信息,如This is a log entry
          • 更多格式屬性可以在這里找到

          要指定格式,我們使用"%(component)s"約定,例如"%(levelname)s". 例如,默認格式表示為"%(levelname)s:%(name)s:%(message)s". 這將在下一節中詳細說明。

          文件中的基本日志記錄

          在了解了日志記錄組件之后,我們準備記錄一些信息!日志記錄可以這樣完成,

          import logging
          logging.basicConfig(
              filename="output.log",
              filemode="w",
              level=logging.DEBUG,
              format="%(asctime)s:%(levelname)s:%(message)s",
              datefmt="%Y-%m-%d %I:%M:%S%p",
          )
          
          logging.debug("Log with debug-level severity")
          logging.info("Log with info-level severity")
          logging.warning("Log with warning-level severity")
          logging.error("Log with error-level severity")
          logging.critical("Log with error-level severity")
          
          try:
              raise Exception("Throw exception")
          except Exception as e:
              logging.error("Exception occurred", exc_info=True)

          在上面的例子中,我們使用basicConfig來指定日志配置,

          • filename: 日志文件,項目的相對路徑
          • filemode:保存模式,"a"追加(默認),"w"寫入
          • level: 日志級別,DEBUG表示每一項與級別相同或更嚴重的項目都DEBUG將被記錄
          • format: 日志格式
          • datefmt:asctime日志格式的日期格式
          • encoding: 指定編碼,僅適用于 Python 3.9 版本

          指定配置后,我們可以在代碼中插入日志調用等logging.info()來執行日志記錄。默認情況下,只會記錄日志消息,但我們也可以設置exc_info=True捕獲堆棧跟蹤,如第 19 行所示。

          話雖如此,使用basicConfig實現日志記錄需要在不同的文件中定義配置,這會導致重復的代碼。在下一節中,我們將使用配置文件以可重用和可擴展的方式實現日志記錄。

          日志記錄的高級組件

          對于日志的高級用法,我們可以在配置文件中定義日志配置,使其可重復用于跨多個 Python 文件進行日志記錄。如果以這種方式實現日志記錄,則可以完成更多項目和自定義,并且它建立在上一節中的基本組件之上。

          記錄器

          記錄器公開應用程序代碼直接使用的接口

          記錄器對應name于日志條目中的屬性。默認情況下root選擇記錄器,其設置(例如保存路徑、保存模式、格式等)由處理程序處理(下一節)。

          使用模塊級記錄器是一個很好的約定,這樣模塊名稱而不是root將顯示為name日志條目的屬性。

          如果存在需要多個設置的情況,可以定義并使用自定義記錄器來代替root記錄器。

          模塊級記錄器和自定義記錄器可以這樣實現,

          import logging
          logging.basicConfig(...)
          
          logger=logging.getLogger(__name__)
          
          logger=logging.getLogger("custom_logger")
          
          logger.info("Log with info-level severity")

          請注意,日志調用現在使用logger.info()而不是logging.info()!

          處理程序

          處理程序將日志記錄發送到適當的目的地(類似于日志文件)

          處理程序指定如何保存日志。在前面的部分中,我們僅將日志保存到日志文件中,但還有更多處理日志的方法。這可以通過使用已經為您實現的相關處理程序類來完成。常見的處理程序類包括,

          • StreamHandler: 將消息發送到流,即控制臺
          • FileHandler: 發送消息到磁盤文件
          • RotatingFileHandler:支持最大日志文件大小和日志文件輪換的 FileHandler
          • 可以在logging官方文檔:https://docs.python.org/3/howto/logging.html#useful-handlers,找到更多處理程序類型。

          模塊化:處理程序以模塊化方式實現,因此可以定義處理程序名稱并在不同的記錄器(root或自定義記錄器)之間重用。

          多對一:一個記錄器可以由多個處理程序組成,例如,如果我們希望日志同時出現在控制臺上,StreamHandler使用FileHandler.

          過濾器

          過濾器根據嚴重性確定輸出哪些日志記錄(類似于日志級別)

          過濾器設置日志嚴重級別并記錄指定嚴重級別及以上的所有內容。過濾器與處理程序一起在字段下定義level。

          如果需要更多自定義,例如僅過濾一個特定的嚴重級別,則必須編寫一個 Python 類,并且此過濾器將與處理程序一起定義,但現在位于 field 下filters。

          模塊化:過濾器以模塊化的方式實現,這樣過濾器名稱可以在不同的處理程序中定義和重用。

          多對一:一個處理程序可以由多個過濾器組成。

          格式化程序

          Formatters 指定日志記錄的格式(類似于日志格式)

          格式化程序設置日志條目的格式。格式化程序與處理程序一起定義,在字段下formatter。

          模塊化:格式化程序以模塊化方式實現,這樣格式化程序名稱可以在不同的處理程序中定義和重用。

          一對一:每個處理程序只能有一種日志格式。

          每個處理程序都有一個唯一的文件過濾器格式設置

          由于過濾器和格式化程序是與處理程序一起定義的,因此每個處理程序都有一個唯一的文件過濾器格式設置。如果需要另一個文件(StreamHandlerFileHandler)、過濾器(DEBUGWARN級別)或格式,則應定義單獨的處理程序。

          帶有配置文件的高級日志記錄

          我們現在將使用配置文件實現日志記錄——它比使用basicConfig. 可以在.conf文件或字典中定義配置.py.yml文件

          字典配置可以這樣定義,

          import logging.config
          
          
          class LevelOnlyFilter:
              def __init__(self, level):
                  self.level=level
          
              def filter(self, record):
                  return record.levelno==self.level
          
          
          LOGGING_CONFIG={
              "version": 1,
              "loggers": {
                  "": {  # root logger
                      "level": "DEBUG",
                      "propagate": False,
                      "handlers": ["stream_handler", "file_handler"],
                  },
                  "custom_logger": {
                      "level": "DEBUG",
                      "propagate": False,
                      "handlers": ["stream_handler"],
                  },
              },
              "handlers": {
                  "stream_handler": {
                      "class": "logging.StreamHandler",
                      "stream": "ext://sys.stdout",
                      "level": "DEBUG",
                      "filters": ["only_warning"],
                      "formatter": "default_formatter",
                  },
                  "file_handler": {
                      "class": "logging.FileHandler",
                      "filename": "output.log",
                      "mode": "w",
                      "level": "DEBUG",
                      "formatter": "default_formatter",
                  },
              },
              "filters": {
                  "only_warning": {
                      "()": LevelOnlyFilter,
                      "level": logging.WARN,
                  },
              },
              "formatters": {
                  "default_formatter": {
                      "format": "%(asctime)s-%(levelname)s-%(name)s::%(module)s|%(lineno)s:: %(message)s",
                  },
              },
          }
          
          logging.config.dictConfig(LOGGING_CONFIG)
          logger=logging.getLogger(__name__)

          我們可以觀察到字典配置被分成幾個部分

          • version(第 13 行):將版本號表示為整數
          • loggers((第 14-25 行):定義根和自定義記錄器,由一個或多個處理程序組成
          • handlers(第 26-41 行):定義記錄器中使用的自定義處理程序,包括特定的文件過濾器格式設置
          • filters(第 42-47 行):定義在處理程序中使用的自定義過濾器
          • formatters(第 48-53 行):定義在處理程序中使用的自定義格式化程序

          具有.conf文件的等效實現可以是這樣的,

          [loggers]
          keys=root,customLogger
          
          [handlers]
          keys=streamHandler,fileHandler
          
          [formatters]
          keys=defaultFormatter
          
          [logger_root]
          level=DEBUG
          propagate=0
          handlers=streamHandler,fileHandler
          
          [logger_customLogger]
          level=DEBUG
          propagate=0
          handlers=streamHandler
          qualname=customLogger
          
          [handler_streamHandler]
          class=StreamHandler
          args=(sys.stdout,)
          level=DEBUG
          formatter=defaultFormatter
          
          [handler_fileHandler]
          class=FileHandler
          args=("output.log", "w")
          level=DEBUG
          formatter=defaultFormatter
          
          [formatter_defaultFormatter]
          format=%(asctime)s:%(levelname)s:%(name)s:%(module)s:%(funcName)s:%(lineno)s:%(message)s

          要使用中定義的配置初始化記錄器logging.conf

          import logging.config 
          logging.config .fileConfig("logging.conf") 
          logger=logging.getLogger(__name__)

          比較dictConfigfileConfig,字典實現是首選,因為它更新并且能夠支持更多功能,例如使用自定義過濾器。

          比較logging.configlogging.basicConfig,使用配置文件可以減少重復代碼的數量,并將配置抽象到單獨的字典或配置文件中,這是跨多個文件執行日志記錄的首選方式。

          常見問題

          在本節中,我將討論使用配置文件實現日志記錄的一些常見問題和注意事項。

          日志配置覆蓋

          有幾種方式可以發生日志配置覆蓋。

          №1:同時使用logging.basicConfiglogging.config

          如果不同的文件使用不同的方法來實例化記錄器,并且在這些文件之間進行了一些導入,使得日志配置中存在沖突,則logging.config實現優先logging.basicConfig并被覆蓋。

          №2:在記錄器級別與處理程序級別定義的日志級別

          如果您在字典和logging.conf文件中注意到,日志級別被定義了兩次,一次在記錄器定義中,另一次在處理程序定義中。較高的嚴重級別優先,其次是記錄器級別優先于處理程序級別。

          為了使這項工作對您有利,我們可以將記錄器級別設置為最低嚴重性,DEBUG并使用處理程序級別來控制級別。如果一個級別應該跨多個處理程序標準化,請隨意在記錄器定義中定義級別。

          繼承

          在繼承期間,日志將被傳遞給記錄器及其高級(祖先)記錄器,從而導致日志條目重復。默認情況下,所有自定義記錄器都從root記錄器繼承。

          為了防止繼承導致重復日志,我們可以在配置中定義記錄器時指定propagate字段。False

          希望您對日志記錄的組件以及如何使用配置文件以可重用和可擴展的方式實現它有更多的了解!與普通的打印語句相比,日志記錄有助于開發人員更好地控制和理解代碼庫,并且在調試大型項目中的代碼時特別有用。

          感謝您的閱讀!如果您喜歡這篇文章,請隨時分享

          文轉載自微信公眾號“前端先鋒”(jingchengyideng)。

          每個前端都會用 JavaScript 控制臺打開日志或調試。但是 console 對象比 console.log() 有更多的東西。

          計算屬性名稱

          ES6 的計算屬性名稱特別有用,因為它們可以通過在變量周圍添加一對大括號來幫你識別的變量。

          const x=1, y=2, z=3; 
           
          console.log({x, y, z}); // {x: 1, y: 2, z: 3} 

          console.trace()

          console.trac() 與 console.log() 完全相同,但它也會輸出整個棧跟蹤,能讓你確切地知道到底發生了什么。

          const outer=()=> { 
            const inner=()=> console.trace('Hello'); 
            inner(); 
          }; 
           
          outer(); 
          /* 
            Hello 
            inner @ VM207:3 
            outer @ VM207:5 
            (anonymous) @ VM228:1 
          */ 

          console.group()

          console.group() 可以把日志分組為可折疊的結構,當有多個日志時特別有用。

          console.group('Outer');           // 創建一個名為 'Outer' 的組 
          console.log('Hello');             // 在 'Outer' 組中輸出日志 
          console.groupCollapsed('Inner');  // 創建一個名為 'Inner' 的組,折疊狀態 
          console.log('Hellooooo');         // 在 'Inner' 組中輸出日志 
          console.groupEnd();               // 結束當前組, 'Inner' 
          console.groupEnd();               // 結束當前組, 'Outer' 
          console.log('Hi');                // 在組外輸出日志 

          日志級別

          除了 console.log() 之外,還有其他一些日志記錄級別,例如 [console.debug()](https://developer.mozilla.org/en-US/docs/Web/API/Console /debug)、 console.info()、 console.warn()和 console.error()。

          console.debug('Debug message'); 
          console.info('Useful information'); 
          console.warn('This is a warning'); 
          console.error('Something went wrong!'); 

          console.assert()

          console.assert() 提供了一種簡便的方法,僅在斷言失敗時將某些內容記錄為錯誤(例如當第一個參數為 false 時),否則完全跳過日志。

          const value=10; 
           
          console.assert(value===10, 'Value is not 10!'); // 不輸出日志 
          console.assert(value===20, 'Value is not 20!'); // 輸出日志:"Value is not 20!" 

          console.count()

          可以用 console.count() 來統計一段代碼執行了多少次。

          Array.from({ length: 4 }).forEach( 
            ()=> console.count('items')  // 名為 items 的計數器 
          ); 
          /* 
            items: 1 
            items: 2 
            items: 3 
            items: 4 
          */ 
          console.countReset('items');  // 重置計數器 

          console.time()

          console.time() 提供了一種快速檢查代碼性能的方法,但是由于精度較低,不可用于真正的基準測試。

          console.time('slow comp');     
          console.timeLog('slow comp');  
          console.timeEnd('slow comp');  

          CSS

          最后一個,還可以在 console.log() 中用 %c 字符串替換表達式將 CSS 應用于日志的各個部分。


          主站蜘蛛池模板: 日韩高清一区二区三区不卡| 乱码人妻一区二区三区| 精品国产一区二区三区麻豆| 国产成人无码精品一区不卡| 亚洲影视一区二区| 国产一区在线视频| 区三区激情福利综合中文字幕在线一区 | 波多野结衣一区在线| 亚洲综合在线一区二区三区| 无码少妇一区二区| 亚洲人成人一区二区三区| 无码人妻AⅤ一区二区三区水密桃 无码欧精品亚洲日韩一区夜夜嗨 无码毛片一区二区三区中文字幕 无码毛片一区二区三区视频免费播放 | 无码AV一区二区三区无码| 无码福利一区二区三区| 精品国产鲁一鲁一区二区| 亚洲国产日韩一区高清在线| 制服丝袜一区二区三区| 久久久久人妻一区精品 | 国产精品视频一区二区三区经| 久久国产精品亚洲一区二区| 日本不卡免费新一区二区三区| 国产在线精品一区二区三区直播| 国产精品亚洲综合一区| 国模无码人体一区二区| 国产精品高清一区二区三区| 国产一区二区免费| 中文字幕一区二区三区5566| 日本激情一区二区三区| 亚洲一区二区三区在线观看网站| 中文精品一区二区三区四区 | 日韩精品一区二区三区影院| 精品3d动漫视频一区在线观看| 一区二区中文字幕在线观看| 视频一区二区中文字幕| 久久se精品一区精品二区国产| 成人精品一区二区三区不卡免费看| 中文无码AV一区二区三区| 久久4k岛国高清一区二区| 麻豆高清免费国产一区| 国产未成女一区二区三区 | 福利一区在线视频|