-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Logging zh TW
ASF允許您自訂執行期間使用的紀錄日誌模組。 您可以將叫做NLog.config
的特定檔案存放至應用程式的資料夾中來達成自訂。 您可以在NLog Wiki中閱讀完整的文件,但除此之外,您也可以在這裡找到一些有用的範例。
預設情形下,ASF會記錄於ColoredConsole
(標準輸出)及File
中。 File
紀錄包含在程式資料夾中的log.txt
檔案及用於歸檔的logs
資料夾中。
使用自訂NLog設定會自動停用預設的ASF設定,您的設定會完全覆寫預設的ASF紀錄,這代表例如您想要保留我們的ColoredConsole
目標,就必須自行定義。 這使您不只能夠新增額外的紀錄目標,還可以停用或修改預設的目標。
若您想要使用不受任何修改的預設ASF紀錄,就什麼也不需要做⸺您也不需要在自訂的NLog.config
中定義它。 若您不想要修改預設ASF紀錄,就不要使用自訂的NLog.config
。 不過做為參考,硬編碼的ASF預設紀錄等同於:
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="https://nlog-project.org/schemas/NLog.xsd" xsi:schemaLocation="NLog NLog.xsd" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance">
<targets>
<target xsi:type="ColoredConsole" name="ColoredConsole" layout="${date:format=yyyy-MM-dd HH\:mm\:ss}|${processname}-${processid}|${level:uppercase=true}|${logger}|${message}${onexception:inner= ${exception:format=toString,Data}}" />
<target xsi:type="File" name="File" archiveFileName="${currentdir}/logs/log.{#}.txt" archiveNumbering="Rolling" archiveOldFileOnStartup="true" cleanupFileName="false" concurrentWrites="false" deleteOldFileOnStartup="true" fileName="${currentdir}/log.txt" layout="${date:format=yyyy-MM-dd HH\:mm\:ss}|${processname}-${processid}|${level:uppercase=true}|${logger}|${message}${onexception:inner= ${exception:format=toString,Data}}" maxArchiveFiles="10" />
<!-- 在ASF的IPC介面啟動時,下列將變為活動狀態 -->
<target type="History" name="History" layout="${date:format=yyyy-MM-dd HH\:mm\:ss}|${processname}-${processid}|${level:uppercase=true}|${logger}|${message}${onexception:inner= ${exception:format=toString,Data}}" maxCount="20" />
</targets>
<rules>
<!-- 下列項指定了ASP.NET(IPC)紀錄,我們宣告它們,因此我們最頂層的Debug catch-all在預設情形下不包含ASP.NET紀錄 -->
<logger name="Microsoft*" finalMinLevel="Warn" writeTo="ColoredConsole" />
<logger name="Microsoft.Hosting.Lifetime*" finalMinLevel="Info" writeTo="ColoredConsole" />
<logger name="System*" finalMinLevel="Warn" writeTo="ColoredConsole" />
<logger name="*" minlevel="Debug" writeTo="ColoredConsole" />
<!-- 下列項指定了ASP.NET(IPC)紀錄,我們宣告它們,因此我們最頂層的Debug catch-all在預設情形下不包含ASP.NET紀錄 -->
<logger name="Microsoft*" finalMinLevel="Warn" writeTo="File" />
<logger name="Microsoft.Hosting.Lifetime*" finalMinLevel="Info" writeTo="File" />
<logger name="System*" finalMinLevel="Warn" writeTo="File" />
<logger name="*" minlevel="Debug" writeTo="File" />
<!-- 在ASF的IPC介面啟用時,下列將變為活動狀態 -->
<!-- 下列項指定了ASP.NET(IPC)紀錄,我們宣告它們,因此我們最頂層的Debug catch-all在預設情形下不包含ASP.NET紀錄 -->
<logger name="Microsoft*" finalMinLevel="Warn" writeTo="History" />
<logger name="Microsoft.Hosting.Lifetime*" finalMinLevel="Info" writeTo="History" />
<logger name="System*" finalMinLevel="Warn" writeTo="History" />
<logger name="*" minlevel="Debug" writeTo="History" />
</rules>
</nlog>
ASF含有一些不錯的程式碼技巧,可以增強與NLog的整合,使您可以更輕鬆地抓取特定訊息。
NLog特定的${logger}
變數將始終用來識別訊息來源⸺可以是您的Bot之一的BotName
;若訊息直接來自ASF程序,也可以是ASF
。 透過這種方式,您可以依據記錄器的名稱輕鬆抓取特定Bot或(只抓取)ASF程序的訊息,而不是全部。
ASF會嘗試依據NLog提供的記錄級別適當地標示訊息,使您可以只抓取來自特定記錄級別的特定訊息,而不是全部。 當然,特定訊息的記錄級別無法自訂,因為這是ASF硬編碼所決定的訊息嚴重程度,但您仍絕對可以使ASF更加/更少的「沉默」,來符合您的需求。
ASF也會記錄額外資訊,例如在Trace
的記錄級別中就包含使用者使用者/聊天訊息。 預設的ASF紀錄只記錄了Debug
級別及以上的訊息,它隱藏了額外訊息,因為大多數使用者並不需要它們,況且這些雜項輸出可能會掩蓋掉重要訊息。 但是您可以透過重新啟用Trace
記錄級別來使用該訊息,特別是您只需要記錄某個特定Bot及您感興趣的特定事件的時候。
一般來說,ASF試圖讓您盡可能地簡單且方便,只記錄您想要的訊息,而不是強迫您透過grep
等第三方工具來手動過濾它。 只需依照下列說明正確地設定NLog,您就應該能夠使用自訂目標(例如整個資料庫)指定的非常複雜的記錄規則。
關於版本控制⸺ASF嘗試始終在發布時提供當時NuGet上最新版的NLog。 您應該能夠使用所有您能在NLog Wiki上找到的ASF功能⸺只需要確保您也使用最新版的ASF。
作為ASF整合的一部份,ASF也支援包含其他ASF NLog紀錄的目標,這將在下列說明。
讓我們從簡單的地方開始。 我們先只使用ColoredConsole目標。 我們初始的NLog.config
看起來像這樣:
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="https://nlog-project.org/schemas/NLog.xsd" xsi:schemaLocation="NLog NLog.xsd" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance">
<targets>
<target xsi:type="ColoredConsole" name="ColoredConsole" />
</targets>
<rules>
<logger name="*" minlevel="Debug" writeTo="ColoredConsole" />
</rules>
</nlog>
上述設定的解釋十分簡單:我們定義一個記錄目標,為ColoredConsole
,然後我們將Debug
及更高級別的所有記錄器(*
)重新導向至先前定義的ColoredConsole
目標。 就是這樣。
若您現在以上述的NLog.config
啟動ASF,只有ColoredConsole
目標會被啟用,且不論ASF硬編碼的NLog設定為何,ASF都不會寫入File
。
現在,假設我們不喜歡預設格式${longdate}|${level:uppercase=true}|${logger}|${message}
,我們只想記錄訊息。 我們可以透過修改目標的布局來做到。
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="https://nlog-project.org/schemas/NLog.xsd" xsi:schemaLocation="NLog NLog.xsd" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance">
<targets>
<target xsi:type="ColoredConsole" name="ColoredConsole" layout="${message}" />
</targets>
<rules>
<logger name="*" minlevel="Debug" writeTo="ColoredConsole" />
</rules>
</nlog>
若您現在啟動ASF,就會注意到日期、級別及記錄器名稱都消失了⸺只留下格式為Function() Message
的ASF訊息。
我們還可以修改設定以記錄多個目標。 讓我們同時記錄到ColoredConsole
和File中。
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="https://nlog-project.org/schemas/NLog.xsd" xsi:schemaLocation="NLog NLog.xsd" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance">
<targets>
<target xsi:type="ColoredConsole" name="ColoredConsole" />
<target xsi:type="File" name="File" fileName="${currentdir}/NLog.txt" deleteOldFileOnStartup="true" />
</targets>
<rules>
<logger name="*" minlevel="Debug" writeTo="ColoredConsole" />
<logger name="*" minlevel="Debug" writeTo="File" />
</rules>
</nlog>
現在,我們已將全部內容記錄到ColoredConsole
和File
中了。 您是否注意到您還可以指定自訂的fileName
與額外選項呢?
最後,ASF使用著各種記錄級別,讓您更容易理解發生的事情。 我們可以利用它,來修改紀錄的嚴重程度。 假設我們要將所有訊息(Trace
)記錄至File
中,但只記錄Warning
及更高的訊息級別至ColoredConsole
。 我們可以修改rules
來達成:
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="https://nlog-project.org/schemas/NLog.xsd" xsi:schemaLocation="NLog NLog.xsd" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance">
<targets>
<target xsi:type="ColoredConsole" name="ColoredConsole" />
<target xsi:type="File" name="File" fileName="${currentdir}/NLog.txt" deleteOldFileOnStartup="true" />
</targets>
<rules>
<logger name="*" minlevel="Warn" writeTo="ColoredConsole" />
<logger name="*" minlevel="Trace" writeTo="File" />
</rules>
</nlog>
就是這樣,現在我們的ColoredConsole
將只會顯示警告及更高級別的訊息,但同時仍將所有訊息記錄到File
中。 您還可以進一步調整它,例如只記錄Info
及更低級別等等。
最後,我們來做一些更進階的操作,將所有來自名為LogBot
的Bot的訊息記錄至檔案中。
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="https://nlog-project.org/schemas/NLog.xsd" xsi:schemaLocation="NLog NLog.xsd" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance">
<targets>
<target xsi:type="ColoredConsole" name="ColoredConsole" />
<target xsi:type="File" name="LogBotFile" fileName="${currentdir}/LogBot.txt" deleteOldFileOnStartup="true" />
</targets>
<rules>
<logger name="*" minlevel="Debug" writeTo="ColoredConsole" />
<logger name="LogBot" minlevel="Trace" writeTo="LogBotFile" />
</rules>
</nlog>
您可以看到我們如何使用上述的ASF整合,並依據${logger}
屬性輕鬆區分訊息來源。
上述範例非常簡單,向您展示了定義您自己的ASF日誌記錄規則是多麼的容易。 您可以使用NLog來做到各種不同的事情,包括複雜目標(例如將紀錄儲存至Database
中)、紀錄輪替(例如移除舊的File
紀錄)、使用自訂Layout
、宣告您自己的<when>
紀錄過濾器等等。 我建議您閱讀整個NLog文件,了解每個可用選項,使您能夠以所需的方式來調整ASF紀錄日誌模組。 這是一個非常強大的工具,自訂ASF紀錄日誌從未如此簡單。
在需要使用者輸入時,ASF將暫時停用包含ColoredConsole
或Console
目標的所有規則。 因此,若您希望在ASF等待使用者輸入時繼續記錄其他目標,您應該使用自己的規則來定義這些目標,如上述範例所示,而不是將很多目標放在相同規則的writeTo
中(除非這就是您想要的行為)。 臨時停用控制台目標是為了在等待使用者輸入時保持控制台乾淨。
ASF包含對聊天紀錄的延伸支援,不只在Trace
記錄級別中記錄所有發送/接收的訊息,還會在事件屬性中暴露與它們相關的額外資訊。 這是因為我們不論如何都需要將聊天訊息作為指令處理,因此記錄這些事件並不會增加任何處理成本,但您可以因此來加入額外的邏輯(例如將ASF當作您的個人Steam聊天存檔)。
名稱 | 描述 |
---|---|
Echo |
bool 型別。 當訊息由我們發送給收件人時設定為true ,否則為false 。 |
Message |
string 型別。 這是實際發送/接收的訊息。 |
ChatGroupID |
ulong 型別。 這是發送/接收訊息的群組聊天ID。 若訊息不是經由群組聊天傳輸則為0 。 |
ChatID |
ulong 型別。 這是發送/接收訊息的ChatGroupID 頻道ID。 若訊息不是經由群組聊天傳輸則為0 。 |
SteamID |
ulong 型別。 這是發送/接收訊息的Steam使用者ID。 在沒有特定使用者參與訊息傳輸時(例如我們傳送訊息給群組聊天),可為0 。 |
本範例基於上述的ColoredConsole
基本範例。 在嘗試理解它之前,我強烈建議您先閱讀上文,來了解NLog紀錄的基礎。
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="https://nlog-project.org/schemas/NLog.xsd" xsi:schemaLocation="NLog NLog.xsd" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance">
<targets>
<target xsi:type="ColoredConsole" name="ColoredConsole" />
<target xsi:type="File" name="ChatLogFile" fileName="${currentdir}/${event-properties:item=ChatGroupID}-${event-properties:item=ChatID}${when:when='${event-properties:item=ChatGroupID}' == 0:inner=-${event-properties:item=SteamID}}.txt" layout="${date:format=yyyy-MM-dd HH\:mm\:ss} ${event-properties:item=Message} ${when:when='${event-properties:item=Echo}' == true:inner=->:else=<-} ${event-properties:item=SteamID}" />
</targets>
<rules>
<logger name="*" minlevel="Debug" writeTo="ColoredConsole" />
<logger name="MainAccount" level="Trace" writeTo="ChatLogFile">
<filters defaultAction="Log">
<when condition="not starts-with('${message}','OnIncoming') and not starts-with('${message}','SendMessage')" action="Ignore" />
</filters>
</logger>
</rules>
</nlog>
我們以基本的ColoredConsole
為例,並在之後對其延伸。 首先,我們為每個群組頻道及Steam使用者準備了一個永久的聊天紀錄檔案⸺這要歸功於ASF向我們公開額外屬性。 我們還決定使用一種自訂布局,只寫入當前日期、訊息、發送/接收資訊及Steam使用者本身。 最後,我們啟用的聊天紀錄規則只適用於Trace
級別、MainAccount
Bot及聊天紀錄相關的函數(用於接收訊息的OnIncoming*
與發送ASF訊息的SendMessage*
)。
上述範例會在與ArchiBot交談時生成0-0-76561198069026042.txt
檔案:
2018-07-26 01:38:38 how are you doing? -> 76561198069026042
2018-07-26 01:38:38 I'm doing great, how about you? <- 76561198069026042
Of course this is just a working example with a few nice layout tricks showed in practical manner. You can further expand this idea to your own needs, such as extra filtering, custom order, personal layout, recording only received messages and so on.
In addition to standard NLog logging targets (such as ColoredConsole
and File
explained above), you can also use custom ASF logging targets.
For maximum completeness, definition of ASF targets will follow NLog documentation convention.
As you can guess, this target uses Steam chat messages for logging ASF messages. You can configure it to use either a group chat, or private chat. In addition to specifying a Steam target for your messages, you can also specify botName
of the bot that is supposed to send those.
Supported in all environments used by ASF.
<targets>
<target type="Steam"
name="String"
layout="Layout"
chatGroupID="Ulong"
steamID="Ulong"
botName="Layout" />
</targets>
Read more about using the Configuration File.
name - Name of the target.
layout - Text to be rendered. Layout Required. Default: ${level:uppercase=true}|${logger}|${message}
chatGroupID - ID of the group chat declared as 64-bit long unsigned integer. 非必要。 Defaults to 0
which will disable group chat functionality and use private chat instead. When enabled (set to non-zero value), steamID
property below acts as chatID
and specifies ID of the channel in this chatGroupID
that the bot should send messages to.
steamID - SteamID declared as 64-bit long unsigned integer of target Steam user (like SteamOwnerID
), or target chatID
(when chatGroupID
is set). Required. Defaults to 0
which disables logging target entirely.
botName - Name of the bot (as it's recognized by ASF, case-sensitive) that will be sending messages to steamID
declared above. 非必要。 Defaults to null
which will automatically select any currently connected bot. It's recommended to set this value appropriately, as SteamTarget
does not take into account many Steam limitations, such as the fact that you must have steamID
of the target on your friendlist. This variable is defined as layout type, therefore you can use special syntax in it, such as ${logger}
in order to use the bot that generated the message.
In order to write all messages of Debug
level and above, from bot named MyBot
to steamID of 76561198006963719
, you should use NLog.config
similar to below:
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="https://nlog-project.org/schemas/NLog.xsd" xsi:schemaLocation="NLog NLog.xsd" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance">
<targets>
<target type="Steam" name="Steam" steamID="76561198006963719" botName="MyBot" />
</targets>
<rules>
<logger name="*" minlevel="Debug" writeTo="Steam" />
</rules>
</nlog>
Notice: Our SteamTarget
is custom target, so you should make sure that you're declaring it as type="Steam"
, NOT xsi:type="Steam"
, as xsi is reserved for official targets supported by NLog.
When you launch ASF with NLog.config
similar to above, MyBot
will start messaging 76561198006963719
Steam user with all usual ASF log messages. Keep in mind that MyBot
must be connected in order to send messages, so all initial ASF messages that happened before our bot could connect to Steam network, won't be forwarded.
Of course, SteamTarget
has all typical functions that you could expect from generic TargetWithLayout
, so you can use it in conjunction with e.g. custom layouts, names or advanced logging rules. The example above is only the most basic one.
This target is used internally by ASF for providing fixed-size logging history in /Api/NLog
endpoint of ASF API that can be afterwards consumed by ASF-ui and other tools. In general you should define this target only if you're already using custom NLog config for other customizations and you also want the log to be exposed in ASF API, e.g. for ASF-ui. It can also be declared when you'd want to modify default layout or maxCount
of saved messages.
Supported in all environments used by ASF.
<targets>
<target type="History"
name="String"
layout="Layout"
maxCount="Byte" />
</targets>
Read more about using the Configuration File.
name - Name of the target.
layout - Text to be rendered. Layout Required. Default: ${date:format=yyyy-MM-dd HH\:mm\:ss}|${processname}-${processid}|${level:uppercase=true}|${logger}|${message}${onexception:inner= ${exception:format=toString,Data}}
maxCount - Maximum amount of stored logs for on-demand history. 非必要。 Defaults to 20
which is a good balance for providing initial history, while still keeping in mind memory usage that comes out of storage requirements. Must be greater than 0
.
Be careful when you decide to combine Debug
logging level or below in your SteamTarget
with steamID
that is taking part in the ASF process. This can lead to potential StackOverflowException
because you'll create an infinite loop of ASF receiving given message, then logging it through Steam, resulting in another message that needs to be logged. Currently the only possibility for it to happen is to log Trace
level (where ASF records its own chat messages), or Debug
level while also running ASF in Debug
mode (where ASF records all Steam packets).
In short, if your steamID
is taking part in the same ASF process, then the minlevel
logging level of your SteamTarget
should be Info
(or Debug
if you're also not running ASF in Debug
mode) and above. Alternatively you can define your own <when>
logging filters in order to avoid infinite logging loop, if modifying level is not appropriate for your case. This caveat also applies to group chats.