Log services: Difference between revisions

Lioncache (talk | contribs)
Rename ILogger command 0 from Initialize to Log. I doubt the original service name is Initialize, and this is more in line with what the actual function does; given this is used heavily by some games to fire out debug info.
 
(11 intermediate revisions by 4 users not shown)
Line 1: Line 1:
= lm =
= lm =
This is "nn::lm::ILogService".
This is "nn::lm::ILogService".
This service is stubbed on retail, with all the commands/interfaces being present but returning success and doing nothing.


{| class="wikitable" border="1"
{| class="wikitable" border="1"
Line 6: Line 8:
! Cmd || Name
! Cmd || Name
|-
|-
| 0 || OpenLogger
| 0 || [[#OpenLogger]]
|}
 
== OpenLogger ==
 
Takes an input u64 value representing a process ID and returns an [[#ILogger]] instance.
 
= lm:get =
This is "nn::lm::ILogGetter". This service doesn't exist on retail.
 
This service can be used to retrieve log messages (only the TextLog field, see [[#Logging]])
 
{| class="wikitable" border="1"
|-
! Cmd || Name
|-
| 0 || [[#StartLogging]]
|-
| 1 || [[#StopLogging]]
|-
| 2 || [[#GetLog]]
|}
|}


== ILogger ==
== StartLogging ==
Takes no input and no output, and just sets a global flag to true.
 
== StopLogging ==
Same as above, but the flag is set to false.
 
== GetLog ==
Takes an output type-0x22 buffer, returns two output u64s (read size and packet drop count)
The flag mentioned above is not checked here, as it is used in a different place (see [[#Logging]])
 
= ILogger =
This is "nn::lm::ILogger".
This is "nn::lm::ILogger".


Line 16: Line 48:
! Cmd || Name
! Cmd || Name
|-
|-
| 0 || Log
| 0 || [[#Log]]
|-
| 1 || [3.0.0+] [[#SetDestination]]
|-
| 2 || [20.0.0+] TransmitHashedLog
|-
| 3 || [20.0.0+] DevNotify
|}
 
== Log ==
 
Takes a type-0x21 input buffer containing the message to log.
Will always return successfully.
 
== SetDestination ==
 
Takes an input u32 mask value indicating the logging destinations to send incoming log messages to. This is stored as a global value. The mask entries are as follows:
 
{| class="wikitable" border="1"
|-
! Value || Description
|-
| 1 || TMA
|-
| 2 || UART
|-
| 4 || UART when sleeping
|-
| 0xFFFF || Log to all destinations
|}
 
= LogPacketHeader =
This is "nn::lm::detail::LogPacketHeader"
 
{| class="wikitable" border="1"
|-
! Offset || Size || Description
|-
| 0x0 || 0x8 || Process ID
|-
| 0x8 || 0x8 || Thread ID
|-
| 0x10 || 0x1 || [[#LogPacketFlags]]
|-
| 0x11 || 0x1 || Padding/reserved
|-
| 0x12 || 0x1 || [[#LogSeverity]]
|-
|-
| 1 || [3.0.0+] SetDestination
| 0x13 || 0x1 || Verbosity
|-
| 0x14 || 0x4 || Payload size
|}
|}


= lm:get =
= LogPacketFlags =
This is "nn::lm::ILogGetter".
 
{| class="wikitable" border="1"
|-
! Value || Name
|-
| 1 || Head
|-
| 2 || Tail
|-
| 4 || LittleEndian
|}
 
= Binary header =
Binary log files saved in SD card have this extra header (see [[#Logging]])
 
{| class="wikitable" border="1"
|-
! Offset || Size || Description
|-
| 0x0 || 0x4 || Magic ("hphp")
|-
| 0x4 || 0x1 || Version (1)
|-
| 0x5 || 0x3 || Padding/reserved
|}
 
= LogSeverity =
This is "nn::diag::LogSeverity"
 
{| class="wikitable" border="1"
|-
! Value || Name
|-
| 0 || Trace
|-
| 1 || Info
|-
| 2 || Warn
|-
| 3 || Error
|-
| 4 || Fatal
|}
 
= LogDataChunkKey =
 
{| class="wikitable" border="1"
|-
! Value || Name || Description
|-
| 0 || LogSessionBegin || Special field sent when a process starts logging (see [[#Logging]])
|-
| 1 || LogSessionEnd || Special field sent when a process finishes logging (see [[#Logging]])
|-
| 2 || TextLog || Actual log text.
|-
| 3 || LineNumber || Line number.
|-
| 4 || FileName || File name.
|-
| 5 || FunctionName || Function name.
|-
| 6 || ModuleName || Module name.
|-
| 7 || ThreadName || Thread name.
|-
| 8 || LogPacketDropCount || Special field containing the amount of packets missed (failed to log/flush, see [[#Logging]])
|-
| 9 || UserSystemClock  || Time value.
|-
| 10 || ProcessName || Process name.
|}
 
= Data chunks =
Data chunks (log packet data fields) follow this format:


{| class="wikitable" border="1"
{| class="wikitable" border="1"
|-
|-
! Cmd || Name
! Offset || Size || Description
|-
| 0x0 || Variable (normally 0x1) || [[#LogDataChunkKey]] in LEB128 format
|-
| Variable || Variable (normally 0x1) || Chunk size in LEB128 format
|-
| Variable || Chunk size || Chunk data
|}
 
= Log packet =
 
{| class="wikitable" border="1"
|-
|-
| 0 || StartLogging
! Offset || Size || Description
|-
|-
| 1 || StopLogging
| 0x0 || 0x18 || [[#LogPacketHeader]]
|-
|-
| 2 || GetLog
| 0x18 || Variable || Data chunks
|}
|}


This service doesn't normally exist on retail.
= Logging =
 
LogManager uses two separate threads: a flushing thread and a htcs thread (main thread is handling both IPC and PM module requests):
 
* The flushing calls Flush() on the "LogBuffer" object, which is the object responsible for flushing logged data though the other objects, and sends a LogPacketDropCount packet via the EventLogTransmitter object (see below) if there any dropped packets and the flushing succeeds - this is done in a loop, waiting until the process starts finalization.
 
* The htcs thread continously reads from the server connection, and will close and reopen the client socket if the connection happened to be lost - this is done in a loop, waiting until the process starts finalization.
 
Different global objects are used for different purposes:
 
* SdCardLogging object - saves logs on the SD card, if both <code>lm!sd_card_log_output_directory</code> and <code>lm!enable_sd_card_logging</code> are present and the last one is true:
** The file name format used is <code>sd:/<log_output_directory>/<serial_no>_<year><month><day><hour><min><sec>[_<extra_index>].nxbinlog</code>, where the extra index is added if the file is already present (several logs being saved at the same time), with a maximum value of 100 (otherwise the saving fails).
** These binary files contain multiple log packets, always preceded by a binary header (see above).
** A single file is used for all the log packets, if the SD card gets ejected or something similar happens the code will re-mount it when it's ready and create a new file.
 
* LogServerProxy object - sends log data via HTCS (see [[TMA_services]])
 
* CustomSinkBuffer object - retains log data which can be later retrieved by [[#lm:get]]:
** When processes log via [[#lm]] service, some code analyzes the log packet, locates the TextLog ([[#LogDataChunkKey]]) chunk (if present) and saves it's contents in a global buffer (therefore, only the actual log message gets retained).
** Log packets are only analyzed/retained after enabling it (by calling [[#StartLogging]]), and the [[#GetLog]] command just reads data from the global buffer.
** The analyzing code also keeps track of which packets are "missed" (skipped/not properly logged), and that missed packet count can be also retrieved on the [[#GetLog]] command.
** When the global buffer is full, nothing will get logged until a process reads the logged data, cleaning the buffer.
 
* EventLogTransmitter object - sends special log packets (event logs):
** When an [[#ILogger]] gets created, this object will send a packet containing the logger's process ID and a LogSessionBegin chunk, telling the remote connection that a new process has started logging. Analogously, when the logger gets destroyed, a simple packet with the process ID and a LogSessionEnd chunk gets sent, telling the remote connection that the process has stopped logging.
** As mentioned above, the flush thread will tell this object to send a simple packet with a LogPacketDropCount chunk after flushing succeeds (and if there any dropped packets).
** These event log packets are logged via the LogBuffer object, like process logs, but they are not analized by the CustomSinkBuffer object since they have no text to be saved.
 
* LogBuffer object - responsible for flushing log packets:
** It internally calls the SdCardLogging and LogServerProxy objects when flushing, so that log packets get flushed to both SD card (if enabled) and HTCS.
** It uses a secondary object to flush, alternating between itself and that secondary object when flushing.


[[Category:Services]]
[[Category:Services]]