Appearance
Appearance
Metaplay runs in both the client (via Unity) and the server, and the methods of logging are different for the two platforms. Nevertheless, Metaplay provides platform-agnostic logging tools that work on both the client and the server.
The easiest way to do platform-agnostic logging is to use PlayerModel.Log
from shared code. It is also available in all other models.
[ModelAction(..)]
public class MyExampleAction : PlayerAction
{
public override MetaActionResult Execute(PlayerModel player, bool commit)
{
// There are five levels of logging:
player.Log.Error("Error level log");
player.Log.Warning("Warning level log");
player.Log.Information("Information level log");
player.Log.Debug("Debub level log");
player.Log.Verbose("Verbose level log");
// You can use named or numbered arguments:
player.Log.Information("Player name={Name}, level={Level}", player.PlayerName, player.PlayerLevel);
player.Log.Information("Player name={0}, level={1}", player.PlayerName, player.PlayerLevel);
// PrettyPrint is a handy helper for logging objects with multiple members:
// Note that the PrettyPrint methods only create a wrapper type that is passed
// to the `Log.Debug()` method which performs the actual pretty-printing
player.Log.Debug("Wallet (multi-line): {Wallet}", PrettyPrint.Verbose(player.Wallet));
player.Log.Debug("Wallet (single-line): {Wallet}", PrettyPrint.Compact(player.Wallet));
// Exceptions can also be logged:
Exception ex = new InvalidOperationException("example exception");
player.Log.Warning("Something failed: {Error}", ex);
// It's possible to avoid paying the overhead of handling arguments by
// checking the `Is<Level>Enabled` before invoking the logging call:
if (player.Log.IsDebugEnabled)
player.Log.Debug("Wallet: {Wallet}", player.Wallet.ToString());
return MetaActionResult.Success;
}
}
On the client, these messages are logged directly in the Unity console. On the server, the log events are routed through the corresponding PlayerActor
responsible for the PlayerModel
doing the logging.
When in the context of any MetaReceiveActor
(essentially all Metaplay's actors), you should use the actor's _log
:
public class MyEntity : PersistedEntityActor<..>
{
public void MyMethod()
{
_log.Information("Example logging from within an actor, with parameters {EntityId}", _entityId);
_log.Warning("The same logging levels are also available");
//_log.Verbose("Except not verbose");
}
}
When logging on the server from outside of an Actor:
// Create a logger and specify the source of logging:
IMetaLogger log = MetaLogger.ForContext<SomeClass>(); // create using the name of the class
IMetaLogger log = MetaLogger.ForContext(this.GetType()); // create using the type of this class (useful from base classes)
IMetaLogger log = MetaLogger.ForContext("CustomName"); // specify any source name
// Then log normally:
log.Information("Logging on log level {LogLevel}", LogLevel.Information);
log.Debug("Debug level also works");
You can use Unity's logging methods for client-only logging needs just as you would without Metaplay.
For ad hoc logging that needs to work on both the client and the server, there is also DebugLog
that is always available. This should only be used temporarily for local testing and never in production.
DebugLog.Debug("Debug logging");
DebugLog.Information("Parameter example: {FirstName} {LastName}", "John", "Doe");
As the number of players in a game grows, the logging itself can become a performance or a cost issue due to the volume of log events generated. For this to avoid becoming a problem, there are a few rules of thumb that we recommend following:
Debug
level on the server at a small scale - It's okay to use Debug
level on the server at a small scale, but we recommend switching to Information
at a large scale.Debug
level - You should only log important events on the Information
level. We generally recommend keeping the Information
-level events to a handful per each player-session.On the client, the active log level is configured when initializing the Metaplay SDK:
// Initialize Metaplay SDK.
MetaplayClient.Initialize(new MetaplayClientOptions
{
LoggingOptions = new MetaplayLoggingOptions
{
DefaultLogLevel = LogLevel.Information,
},
...
On the server, the configuration is done using the Working with Runtime Options, i.e., your project's Backend/Server/Config/Options.*.yaml
files:
# Default to Debug:
Logging:
Level: Debug
# In production, override to Information:
Logging:
Level: Information
You can also configure the logging levels at compile-time by specifying one of the following preprocessor #define
s in your project. These can be configured separately for the client and the server.
METAPLAY_LOG_LEVEL_VERBOSE
: No events are omitted at compile time. This is the default on the client.METAPLAY_LOG_LEVEL_DEBUG
: Verbose events are always omitted. This is the default on the server.METAPLAY_LOG_LEVEL_INFORMATION
: Verbose and Debug events are always omitted.METAPLAY_LOG_LEVEL_WARNING
: Only warnings and errors can be logged.METAPLAY_LOG_LEVEL_ERROR
: Only errors can be logged.Specifying one of the defines causes the logging events below that level to be statically omitted during compilation, which removes the performance overhead for logging on the omitted levels.
When running the Game Backend locally, it will print the logs into your terminal window with colour coding for easy reading.
The following keyboard commands are supported:
The behavior for how logs are handled in cloud deployments is presently handled through the configuration of the metaplay-gameserver
Helm chart, which is used to deploy the game backend. For more detailed and up-to-date information about the available options, please refer to the chart README.
The default behavior for game servers in cloud deployments is to log to stdout
. These logs will be captured as part of the cluster's regular log tooling — in Metaplay's case, the standard DaemonSet Promtail deployments and operationalized through cluster-level Loki and Grafana. Along with game server logs, logs from all other pods will also be accessible this way, through the cluster's Grafana interface.
In multi-tenant environments, you can opt to enable the similar Grafana/Loki set up through the metaplay-gameserver
chart, which allows you to gather the logs specific to your game server, as in multi-tenant environments you may not always have the possibility to tap into the cluster-wide tooling.
Additionally, the Helm chart allows you to configure logging type between JSON and text, depending on your preferences.