Logging
In Ergo Framework, a flexible logging system is implemented that allows multiple loggers to exist within a node. These loggers can be configured to receive specific logging levels.
For logging purposes, the gen.Node
and gen.Process
interfaces provide the Log
method. This method returns the gen.Log
interface, which is used for logging messages within the framework.
Using the gen.Log
interface, you can manage the logging level not only for the node but also for each individual process (including meta-processes). There are six standard logging levels that can be set using the SetLevel
method:
gen.LogLevelDebug
gen.LogLevelInfo
gen.LogLevelWarning
gen.LogLevelError
gen.LogLevelPanic
gen.LogLevelDisabled
Additionally, there are specialized logging levels:
gen.LogLevelDefault
: This is the default logging level. When a node starts with this level, it defaults togen.LogLevelInfo
. For applications or processes, the logging level inherits from the node. Meta-processes inherit the logging level of their parent process.gen.LogLevelTrace
: This level is used exclusively for deep debugging. To avoid accidental activation, this level cannot be set through theSetLevel
method of thegen.Log
interface. Instead, it can only be enabled during the startup of a node or process throughgen.NodeOptions.Log.Level
orgen.ProcessOptions.LogLevel
.
By default, the logging level for the node is set to gen.LogLevelInfo
. Processes inherit the node's logging level at startup unless explicitly set in gen.ProcessOptions
.
The SetLogger
method allows you to restrict logging to a specified logger. If no logger is specified, the log message will be delivered to all registered loggers. You can retrieve the list of registered loggers using the Loggers
method of the gen.Node
interface.
The gen.LogLevelDisabled
level can be used to temporarily disable logging, either for the entire node or a specific process.
Furthermore, the gen.Node
interface provides two methods for process-specific logging control:
ProcessLogLevel(pid gen.PID)
: Retrieves the current logging level of a specific process.SetProcessLogLevel(pid gen.PID, level gen.LogLevel)
: Sets the desired logging level for a specific process.
Logger
By default, a node in Ergo Framework uses a standard logger, and its parameters can be configured during node startup via gen.NodeOptions.Log.DefaultLogger
. You have the option to disable the default logger and use a process-based logger or integrate one (or more) loggers from an additional logging library.
If you wish to create your own logger, you simply need to implement the gen.LoggerBehavior
interface. This interface defines the behavior of a logger, allowing you to customize the logging system according to your application's requirements. By implementing this interface, you can control how log messages are processed, formatted, and routed, providing flexibility beyond the default logging system.
To add a new logger, the gen.Node
interface provides two methods:
LoggerAdd(name string, logger gen.LoggerBehavior, filter ...gen.LogLevel)
: This method allows you to add a logger (an object implementing thegen.LoggerBehavior
interface) to the node's logging system.LoggerAddPID(pid gen.PID, name string, filter ...gen.LogLevel)
: This method adds a process as a logger. In this case, the node sends log messages to the specified process. Theact.Actor
class provides a callback methodHandleLog
for handling such log messages.
Both methods accept a filter
argument, which allows you to specify a set of log levels that the logger should handle. For example, if you want your logger to only receive messages at the gen.LogLevelPanic
and gen.LogLevelInfo
levels, you can list them in the filter:
If the filter
argument is not specified, the default set of log levels, gen.DefaultLogFilter
, will be used:
The logging methods of the gen.LoggerBehavior
interface will only be invoked for messages that match the specified logging levels.
Reusing a logger name is not allowed. If a logger with the same name already exists, the LoggerAdd
or LoggerAddPID
function will return the error gen.ErrTaken
. To resolve this, you must first remove the existing logger from the system using the appropriate method: LoggerDelete
or LoggerDeletePID
from the gen.Node
interface.
When a logger is removed from the system, the Terminate
callback method of the gen.LoggerBehavior
interface is called.
The methods of the gen.LoggerBehavior
interface are called synchronously by the node or process. If you are implementing your own logger, it is important to keep this in mind and avoid blocking these calls with complex or time-consuming log message processing.
To mitigate this issue, it is recommended to consider using a process-based logger. In this case, all log messages are placed in the process's mailbox and processed asynchronously, ensuring that the gen.LoggerBehavior
interface methods are not blocked by the logging logic. This approach allows for more efficient handling of log messages without impacting the overall performance of the node or process.
Default logger
When starting a node, you can specify logging parameters using the gen.NodeOptions.Log.DefaultLogger
option. These parameters will be applied to the default logger, which outputs all log messages in text format to a specified output (by default, os.Stdout
). With these options, you can configure:
Output
: The interface used for log message output. To direct log messages to both standard output and a file simultaneously, you can use theio.MultiWriter
function from Golang's standard library:TimeFormat
: Defines the format for the timestamp of log messages. You can use any existing format, such astime.DateTime
(see time package constants), or define your own custom format. By default, the timestamp is output in nanoseconds.IncludeBehavior
: Adds the behavior of the process or meta-process to the log message.IncludeName
: Adds the registered name of the process to the log message, if it exists.Filter
: Specifies the logging levels that the default logger will handle. Leave this field empty to use the default set of levels (gen.DefaultLogFilter
).Disable
: Disables the default logger.
Here is an example of how the standard logger's output might look with these options applied:
The first field is the timestamp of the log message, the second field is the log level, and the third field is the source of the message. The sources can come from various interfaces:
gen.Node.Log()
: Uses the node's name in the form of a CRC32 hash. Example:9F35C982
gen.Process.Log()
: The string representation of the process identifiergen.PID
. Example:<9F35C982.0.1013>
gen.MetaProcess.Log()
: The string representation of the meta-process identifiergen.Alias
. Example:Alias#<9F35C982.123663.24065.0>
gen.Connection.Log()
: String representations of the local and remote nodes. Example:9F35C982-90A29F11
Process-logger
If you want to manage log message streams using the familiar actor model, any process in a running node can serve as a logger. In the act.Actor
implementation, received log messages are passed as the message
argument to the HandleLog
callback method.
To add your actor to the node as a logger, use the LoggerAddPID
method from the gen.Node
interface:
Note that the LoggerAddPID
method of the gen.Node
interface is not available to a process during its initialization state, as the node has not yet recognized the process (see the Process section). Therefore, an actor cannot add itself as a logger within the Init
callback method of the act.ActorBehavior
interface.
When a logger process terminates, it will be automatically removed from the node's logging system.
Implementations of gen.Logger
To extend the capabilities of the Ergo Framework, two additional loggers have been implemented:
colored: Enables colored highlighting for log messages in the console.
rotate: Allows logging to a file with support for log file rotation at specified intervals.
You can disable the default logger and add both of these loggers, enabling colored output in the console while also saving logs to a file with rotation. You can find an example of using them in the demo
project here.
Last updated