Logger
LoadStrike writes runtime logs for you by default. Use this page when you want to understand that default behavior or replace it with your own logger setup.
Matching docs
Search across docs titles, summaries, groups, and section headings.
Use Up and Down Arrow to move through results, then press Enter to open the active page.
No indexed docs matched that search. Try a broader term or open the docs hub.
What this page helps you do
What this page helps you do
LoadStrike writes runtime logs for you by default. Use this page when you want to understand that default behavior or replace it with your own logger setup.
Who this is for
Engineers writing or reviewing scenario code in one of the supported SDKs.
Prerequisites
- A scenario or runtime surface you want to wire correctly in code
By the end
The exact SDK surface you need for this part of the runtime.
Use this page when
Use this reference when you already know the workflow and need the exact Logger API surface in code.
Visual guide
Guide
Default Behavior
Default destinations differ by SDK. Go writes one generated text log per runtime node or process in the configured report folder and does not also mirror normal logs to the console. A single-node run returns one path; clustered or local-cluster execution can return coordinator and agent-indexed paths. See the language tab for the other SDK defaults. The generated file name follows loadstrike-log-<yyyyMMdd_HHmmss>[-coordinator|-agent-<index>][-machine].txt.
Minimum Level
Use WithMinimumLogLevel, withMinimumLogLevel, or with_minimum_log_level when the run should filter out lower-level events. Supported public levels are Verbose, Debug, Information, Warning, Error, and Fatal. In Go, the fluent method and `LoadStrike:MinimumLogLevel` accept those case-insensitive names; aliases, numeric values, and blank values are rejected before workload traffic starts.
Custom Logger Configuration
Use WithLoggerConfig, withLoggerConfig, or with_logger_config when logs need to go somewhere else. In .NET the callback returns a Serilog LoggerConfiguration. Java, Python, TypeScript, and JavaScript use their native logger callback shapes. Go returns a LoggerConfiguration map whose only supported keys are `target`, `format`, `path`, and `minimumLevel`.
Go Logger Values
Go `target` accepts the strings `file`, `stdout`, or `stderr`; `format` accepts the strings `text` or `json`; and `path` is a nonblank string required for an explicit file target and invalid for standard streams. `minimumLevel` accepts either one of the six named strings or the matching loadstrike.LogEventLevel value. An explicit WithMinimumLogLevel value wins over `minimumLevel`, and Information is the default. An explicit file path is safe for single-node runs. Local clustered nodes currently reuse an explicit path and can truncate or contend for it, so omit path in a local cluster and use generated node-specific files.
Go Callback Logs
Information written during initialization, warnings or errors written from scenario and step callbacks, and cleanup logs use the same Go target, format, and minimum-level filter as other run logs. File output is closed before Run returns. Go stdout and stderr records are replayed after the workload process exits rather than streamed live, and a failed run surfaces its bounded diagnostic by panic.
Replacement Rule
A custom logger configuration replaces the default public logger pipeline. If you still want a text log file after overriding the logger, add file output inside your custom logger configuration.
Console Metrics Snapshots
In SDKs that implement the display, DisplayConsoleMetrics shows live request, ok, and fail counters separately from the logger. Go accepts WithDisplayConsoleMetrics and the DisplayConsoleMetrics config key for compatibility, but the current Go runtime does not emit live console snapshots. Use reporting sinks during the run and the final LoadStrikeRunResult for Go counts.
Cluster Behavior
Each Go runtime node or process writes its own log file. Local-cluster child logs share the configured or default report folder and use coordinator or agent-indexed filenames to remain distinct. The final LoadStrikeRunResult includes the collected log paths in LogFiles when the coordinator can observe them.
Language Differences
The core model stays the same across SDKs, but a few helpers and result shapes use language-specific names. Check these notes when you switch languages or compare samples.
Use WithLoggerConfig(() => new LoggerConfiguration(...)) for Serilog sinks, enrichers, and formatting.
Return only target, format, path, and minimumLevel from LoggerConfiguration. target, format, and path are strings; minimumLevel may be a named string or loadstrike.LogEventLevel. File output is owned and closed by LoadStrike; stdout and stderr remain caller-owned process streams.
Use the native logger callback surface for that SDK. Its callback shape differs from the Go destination map and the .NET Serilog configuration.
SDK reference samples
Use these SDK samples to compare how Logger is exposed across the supported languages before you wire it into a full scenario.
If you run these examples locally, add a valid runner key before execution starts. Set it with WithRunnerKey("...") or the config key LoadStrike:RunnerKey.
Logger
using LoadStrike;
using System;
using Serilog;
using Serilog.Events;
var scenario = LoadStrikeScenario
.Create("submit-orders", _ => Task.FromResult(LoadStrikeResponse.Ok(statusCode: "200")))
.WithLoadSimulations(LoadStrikeSimulation.Inject(rate: 10, interval: TimeSpan.FromSeconds(1), during: TimeSpan.FromSeconds(20)));
LoadStrikeRunner.RegisterScenarios(scenario)
.WithReportFolder("./reports")
.WithMinimumLogLevel(LogEventLevel.Information)
.DisplayConsoleMetrics(true)
.WithLoggerConfig(() => new LoggerConfiguration()
.WriteTo.Console()
.WriteTo.File("./custom-logs/orders.log"))
.WithRunnerKey("rkl_your_local_runner_key")
.Run();
package main
import (
"time"
loadstrike "loadstrike.com/sdk/go"
)
func main() {
loadstrike.RegisterScenarios(loadstrike.Empty("logger-demo")).
WithLoggerConfig(loadstrike.LoggerConfigurationFactory(func() loadstrike.LoggerConfiguration {
return loadstrike.LoggerConfiguration{
"target": "stdout",
"format": "json",
"minimumLevel": loadstrike.LogEventLevelVerbose,
}
})).
WithMinimumLogLevel(loadstrike.LogEventLevelWarning). // This explicit level wins.
WithReportingInterval(loadstrike.TimeSpan(5 * time.Second)).
WithRunnerKey("rkl_your_local_runner_key").
Run()
}
import com.loadstrike.runtime.LoadStrikeRuntime.LoadStrikeResponse;
import com.loadstrike.runtime.LoadStrikeRuntime.LoadStrikeLogLevel;
import com.loadstrike.runtime.LoadStrikeRuntime.LoadStrikeLogger;
import com.loadstrike.runtime.LoadStrikeRuntime.LoadStrikeRunner;
import com.loadstrike.runtime.LoadStrikeRuntime.LoadStrikeScenario;
import com.loadstrike.runtime.LoadStrikeRuntime.LoadStrikeSimulation;
import com.loadstrike.runtime.LoadStrikeRuntime.LoadStrikeStep;
import java.util.logging.Logger;
Logger appLogger = Logger.getLogger("loadstrike-demo");
var scenario = LoadStrikeScenario
.create("submit-orders", context -> LoadStrikeStep.run(
"POST /orders",
context,
() -> LoadStrikeResponse.ok("200")
).asReply())
.withLoadSimulations(LoadStrikeSimulation.inject(10, 1d, 20d));
LoadStrikeRunner.registerScenarios(scenario)
.withReportFolder("./reports")
.withMinimumLogLevel(LoadStrikeLogLevel.Warning)
.displayConsoleMetrics(true)
.withLoggerConfig(() -> new LoadStrikeLogger() {
@Override
public void info(String message) {
appLogger.info("[loadstrike] " + message);
}
@Override
public void warn(String message) {
appLogger.warning("[loadstrike] " + message);
}
@Override
public void error(String message) {
appLogger.severe("[loadstrike] " + message);
}
})
.withRunnerKey("rkl_your_local_runner_key")
.run();
from loadstrike_sdk import (
LoadStrikeResponse,
LoadStrikeRunner,
LoadStrikeScenario,
LoadStrikeSimulation,
LoadStrikeStep,
)
import logging
from pathlib import Path
app_logger = logging.getLogger("loadstrike-demo")
if not app_logger.handlers:
Path("./custom-logs").mkdir(parents=True, exist_ok=True)
file_handler = logging.FileHandler("./custom-logs/orders.log", encoding="utf-8")
console_handler = logging.StreamHandler()
formatter = logging.Formatter("%(asctime)s [%(levelname)s] %(message)s")
file_handler.setFormatter(formatter)
console_handler.setFormatter(formatter)
app_logger.addHandler(file_handler)
app_logger.addHandler(console_handler)
app_logger.setLevel(logging.INFO)
class ConsoleLogger:
def debug(self, message: str) -> None:
app_logger.debug(message)
def info(self, message: str) -> None:
app_logger.info(message)
def warn(self, message: str) -> None:
app_logger.warning(message)
def error(self, message: str) -> None:
app_logger.error(message)
scenario = (
LoadStrikeScenario.create(
"submit-orders",
lambda context: LoadStrikeStep.run(
"POST /orders",
context,
lambda: LoadStrikeResponse.ok("200"),
).as_reply(),
)
.with_load_simulations(LoadStrikeSimulation.inject(10, 1, 20))
)
LoadStrikeRunner.register_scenarios(scenario) \
.with_report_folder("./reports") \
.with_minimum_log_level("Warning") \
.display_console_metrics(True) \
.with_logger_config(lambda: ConsoleLogger()) \
.with_runner_key("rkl_your_local_runner_key") \
.run()
import {
LoadStrikeResponse,
LoadStrikeRunner,
LoadStrikeScenario,
LoadStrikeSimulation,
LoadStrikeStep
} from "@loadstrike/loadstrike-sdk";
import { appendFileSync, mkdirSync } from "node:fs";
mkdirSync("./custom-logs", { recursive: true });
const scenario = LoadStrikeScenario
.create("submit-orders", async (context) => {
const step = await LoadStrikeStep.run("POST /orders", context, async () =>
LoadStrikeResponse.ok("200")
);
return step.asReply();
})
.withLoadSimulations(LoadStrikeSimulation.inject(10, 1, 20));
await LoadStrikeRunner.registerScenarios(scenario)
.withReportFolder("./reports")
.withMinimumLogLevel("Warning")
.displayConsoleMetrics(true)
.withLoggerConfig(() => ({
debug: (message) => appendFileSync("./custom-logs/orders.log", `[DBG] ${message}\n`, "utf8"),
info: (message) => {
console.info(message);
appendFileSync("./custom-logs/orders.log", `[INF] ${message}\n`, "utf8");
},
warn: (message) => {
console.warn(message);
appendFileSync("./custom-logs/orders.log", `[WRN] ${message}\n`, "utf8");
},
error: (message) => {
console.error(message);
appendFileSync("./custom-logs/orders.log", `[ERR] ${message}\n`, "utf8");
}
}))
.withRunnerKey("rkl_your_local_runner_key")
.run();
const {
LoadStrikeResponse,
LoadStrikeRunner,
LoadStrikeScenario,
LoadStrikeSimulation,
LoadStrikeStep
} = require("@loadstrike/loadstrike-sdk");
const { appendFileSync, mkdirSync } = require("node:fs");
mkdirSync("./custom-logs", { recursive: true });
(async () => {
const scenario = LoadStrikeScenario
.create("submit-orders", async (context) => {
const step = await LoadStrikeStep.run("POST /orders", context, async () =>
LoadStrikeResponse.ok("200")
);
return step.asReply();
})
.withLoadSimulations(LoadStrikeSimulation.inject(10, 1, 20));
await LoadStrikeRunner.registerScenarios(scenario)
.withReportFolder("./reports")
.withMinimumLogLevel("Warning")
.displayConsoleMetrics(true)
.withLoggerConfig(() => ({
debug: (message) => appendFileSync("./custom-logs/orders.log", `[DBG] ${message}\n`, "utf8"),
info: (message) => {
console.info(message);
appendFileSync("./custom-logs/orders.log", `[INF] ${message}\n`, "utf8");
},
warn: (message) => {
console.warn(message);
appendFileSync("./custom-logs/orders.log", `[WRN] ${message}\n`, "utf8");
},
error: (message) => {
console.error(message);
appendFileSync("./custom-logs/orders.log", `[ERR] ${message}\n`, "utf8");
}
}))
.withRunnerKey("rkl_your_local_runner_key")
.run();
})();
Logger levels, destinations, and formats
Most runs can use the default logger. The Go SDK writes one generated Information-level text log per runtime node or process in the report folder. A single-node run returns one path; clustered execution can return coordinator and agent-indexed paths in LoadStrikeRunResult.LogFiles().
Without logger options, Go writes Information, Warning, Error, and Fatal events to one generated text file per runtime node or process in the configured report folder, or ./reports when no folder is set. Single-node runs return one path; clustered runs can return coordinator and agent-indexed paths. Files are closed before Run() returns.
Accepts Verbose, Debug, Information, Warning, Error, or Fatal. The selected level and higher-priority events are written; names are case-insensitive, while aliases, numeric levels, and blank values are rejected.
The factory returns a LoggerConfiguration map. Its exact supported keys are target, format, path, and minimumLevel. Unknown keys fail before test traffic starts. target, format, and path require strings; minimumLevel accepts a named string or loadstrike.LogEventLevel.
Go accepts file, stdout, or stderr case-insensitively. An explicit file target requires path. A path without target remains a supported shorthand for file output, while stdout and stderr reject any path.
Go accepts text or json case-insensitively and defaults to text. JSON output is newline-delimited, with exactly timestampUtc, level, and message in each object.
Go uses minimumLevel from LoggerConfiguration only when WithMinimumLogLevel has not set a level. An explicit WithMinimumLogLevel value wins regardless of call order; Information is the final default.
Go creates or truncates the selected file for the run, reports the path through LogFiles(), and closes it before returning. An explicit path is safe for single-node use. Local-cluster nodes currently reuse an explicit path and can truncate or contend for it, so omit path there and use generated node-specific files. Blank paths, directory paths, and explicitly configured paths that cannot be opened are rejected without echoing the supplied path in the diagnostic.
Standard-stream targets do not add a LogFiles() entry and are not closed by LoadStrike. Their configured output is replayed to the selected process stream after workload execution stops, including the final failure record; it is not a live stream. Known runner-key text is redacted. A failed Go run panics with a bounded, sanitized diagnostic that does not duplicate the selected logger stream.
Successful init, scenario, step, and cleanup callback log records enter the selected logger once and obey the same target, format, and minimum level as other run logs.
Accepted by Go fluent and JSON configuration for compatibility, but the current Go runtime does not emit live requests, successes, and failures snapshots. It does not change the logger level, target, or format; use reporting sinks and the final result for Go counts.