Skip to main content

Logger

Logger is a static class that provides structured logging for C# functions. Log entries are sent to the Invoke platform over IPC and appear in the function's log stream in real time.

using Invoke;
using System.Text.Json.Nodes;

Logger.Info("Handler started");
Logger.Info(new JsonObject { ["userId"] = 42, ["action"] = "login" });
Logger.Warn("%s has won %d dollars!", "Brian", 100_000);

var child = Logger.GetChild("module", "auth-service");
child.Info("Token validated");

Log Levels

Six log levels are supported, in ascending order of severity:

LevelMethodSeverity
traceLogger.TraceLowest
debugLogger.Debug
infoLogger.InfoDefault
warnLogger.Warn
errorLogger.Error
fatalLogger.FatalHighest

The current minimum level is controlled by Logger.Level. Log calls below the threshold are discarded without sending anything over IPC.

Logger.Level = "warn"; // only warn, error, and fatal will be emitted

Method Signatures

Each level has two overloads.

String message with printf-style formatting

Logger.Info(string msg, params object?[] args)

Formats msg using printf-style specifiers before sending. See Printf Formatting below.

Logger.Info("User %s signed in from %s", username, ipAddress);
Logger.Error("Request failed with status %d", statusCode);

Structured object with optional message

Logger.Info(JsonObject obj, string? msg = null, params object?[] args)

Sends obj as structured details in the log entry. If msg is provided it is printf-formatted and included as the log message.

// Object only — no message
Logger.Info(new JsonObject { ["foo"] = "bar" });

// Object + message
Logger.Warn(
new JsonObject { ["method"] = req.Method, ["path"] = req.Path },
"Incoming request"
);

// Object + formatted message
Logger.Error(
new JsonObject { ["code"] = errorCode },
"Operation failed after %d retries",
retryCount
);

Printf Formatting

The following format specifiers are supported in message strings:

SpecifierBehavior
%sToString() of the argument
%dInteger representation
%iInteger representation (alias for %d)
%fFloating-point representation
%oToString() of the argument
%OToString() of the argument
%jJsonNode.ToJsonString() if the argument is a JsonNode; otherwise ToString()

Any extra arguments beyond the number of format specifiers are appended to the message separated by spaces.

Logger.Info("%s scored %d points (%.1f avg)", "Alice", 120, 24.5);
// → "Alice scored 120 points (24.5 avg)"

var data = new JsonObject { ["id"] = 1, ["name"] = "Alice" };
Logger.Debug("Payload: %j", data);
// → "Payload: {"id":1,"name":"Alice"}"

Logger.Info("Extra args", "appended", "here");
// → "Extra args appended here"

Child Loggers

Logger.GetChild returns a ChildLogger instance that automatically attaches persistent fields to every log entry it emits. Child loggers can themselves spawn further children — bindings accumulate at each level.

GetChild(JsonObject bindings)

Create a child with one or more persistent fields:

var child = Logger.GetChild(new JsonObject
{
["module"] = "payments",
["requestId"] = requestId
});

child.Info("Processing payment");
// details: { "module": "payments", "requestId": "..." }

GetChild(string key, string value)

Shorthand for a single binding:

var child = Logger.GetChild("module", "auth-service");
child.Info("Token validated");
// details: { "module": "auth-service" }

Nesting child loggers

var serviceLogger = Logger.GetChild("service", "api");
var requestLogger = serviceLogger.GetChild("requestId", requestId);

requestLogger.Info("Started");
// details: { "service": "api", "requestId": "..." }

ChildLogger API

ChildLogger exposes the same methods and properties as the static Logger class, plus its own GetChild:

ChildLogger child = Logger.GetChild("module", "worker");

child.Trace(string msg, params object?[] args)
child.Debug(string msg, params object?[] args)
child.Info(string msg, params object?[] args)
child.Warn(string msg, params object?[] args)
child.Error(string msg, params object?[] args)
child.Fatal(string msg, params object?[] args)

// Object overloads (same pattern as Logger)
child.Info(JsonObject obj, string? msg = null, params object?[] args)

child.Level // get/set minimum level
child.IsLevelEnabled(string level) // → bool
child.GetChild(JsonObject bindings) // → ChildLogger
child.GetChild(string key, string value) // → ChildLogger

IsLevelEnabled

Check whether a given level will be emitted before doing expensive work:

if (Logger.IsLevelEnabled("debug"))
{
var snapshot = BuildExpensiveDebugSnapshot();
Logger.Debug(snapshot, "State snapshot");
}

Console Output

Console.WriteLine and Console.Write are automatically redirected to the platform log stream at info level. Console.Error.WriteLine is redirected at error level. You do not need to configure anything; however, using Logger directly is preferred because it supports structured fields and level filtering.

Console.WriteLine("hello"); // → info log: "hello"
Console.Error.WriteLine("oops"); // → error log: "oops"