logging
Skill268 starsChanged 48 days agoApache-2.0View on GitHub
Use when adding or reviewing logging in a QuantConnect/LEAN algorithm. Triggers — code uses `Log`, `Debug`, `Error`, `Quit`; questions like "why are my logs missing", "log quota exceeded", "too many log lines per bar", "how do I log every fill", "where do my prints go", "save backtest data for Research analysis", "log spam in `OnData` / inside loops". Skip when — goal is sending alerts out of the algo (email/SMS/webhook → `notifications` skill).
25 other projects use a version of this.
Adopted by
Most recently taken up by
- codewithmukesh/dotnet-claude-kittheir own version, first seen Nov 8, 2026
- lawless-m/claude-skillstheir own version, first seen Nov 6, 2026
- zdanovichnick/dotnet-pilottheir own version, first seen Nov 6, 2026
- gabrielbauman/skillstheir own version, first seen Nov 1, 2026
- jars-demo/jars-skillstheir own version, first seen Oct 25, 2026
- andr-ca/agentharnesstheir own version, first seen Oct 15, 2026
Used with
Projects with it also use convention-learner, opentelemetry and 10 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
codewithmukeshSkillconvention-learner
Detects and enforces project-specific coding conventions by analyzing existing codebase patterns. Learns naming conventions, folder structure, test organization, and coding style from the existing code. Load when: "conventions", "coding standards", "project patterns", "enforce style", "detect patterns", "learn conventions", "code consistency".
Also in 3 projects that use this
codewithmukeshSkillopentelemetry
OpenTelemetry observability for .NET 10 applications. Covers traces, metrics, and logs using the OpenTelemetry SDK with OTLP export. Includes custom ActivitySource, IMeterFactory metrics, resource configuration, and Aspire Dashboard integration. Load this skill when setting up distributed tracing, custom metrics, OTLP export, or when the user mentions "OpenTelemetry", "OTLP", "traces", "spans", "Activity", "ActivitySource", "metrics", "IMeterFactory", "Meter", "Counter", "Histogram", "Gauge", "telemetry", "observability", "distributed tracing", "OTEL", or "Aspire Dashboard".
Also in 3 projects that use this
MovGP0Skillmodern-csharp
Modern C# style guidance for Bendex and MicroSea code changes, including primary constructors, expression-bodied members, var usage, target-typed new, lambdas, and pattern matching.
Also in 3 projects that use this
junhjangSkillconfiguration
Adding a new config file, adding a field, or wiring a config consumer. Enforces schema validation at startup (no permissive defaults), env-var indirection for secrets, layered config (defaults / per-env / operator-override), hot-reload explicit per field.
Also in 4 projects that use this
wpankSkillcaching
Caching strategies, invalidation, eviction policies, HTTP caching, distributed caching, and anti-patterns. Use when designing cache layers, choosing eviction policies, debugging stale data, or optimizing read-heavy workloads.
Also in 4 projects that use this
HamzaSheikh768Skilldependency-injection
Leverages FastAPI's powerful Depends system for reusable authentication, database sessions, rate limiting, and business logic injection.
Also in 4 projects that use this
Other versions25 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 25
- elie222/inbox-zero★ 13ksame name
- lukevella/rallly★ 5.4ksame name
- epicenter-md/epicenter★ 4.8ksame name
- EpicenterHQ/epicenter★ 4.8ksame name
- golemcloud/golem★ 1.5ksame name
- codewithmukesh/dotnet-claude-kit★ 808same name
- emavgl/oinkoin★ 486same name
- Resgrid/Core★ 238same name
- lawless-m/claude-skills★ 6same name
- zdanovichnick/dotnet-pilot★ 5same name
15 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository39 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- docs-styleSkill
- calendarSkill
- code-qualitySkill
- cryptoSkill
- data-exportSkill
- data-issuesSkill
- debug-algorithmSkill
- debug-performanceSkill
- equity-fundamental-dataSkill
- equity-optionsSkill
- futuresSkill
- historical-data-equity-optionsSkill
- historySkill
- indicatorsSkill
- option-strategiesSkill
- ordersSkill
- pricingSkill
- scheduled-eventsSkill
- universesSkill
- calendarSkill
- code-qualitySkill
- cryptoSkill
- data-exportSkill
- data-issuesSkill
- debug-algorithmSkill
- debug-performanceSkill
- equity-fundamental-dataSkill
- equity-optionsSkill
- futuresSkill
- historical-data-equity-optionsSkill
- historySkill
- indicatorsSkill
- loggingSkill
- option-strategiesSkill
- ordersSkill
- pricingSkill
- scheduled-eventsSkill
- universesSkill
The file
We split this skill into the rules it gives an agent
6 rules. 0 are common, 2 are distinctive, and 4 are very specific to this project.
0
Common
Most of the 20 edited versions we read keep these.
2
Distinctive
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 25
Never log routine HOLD / no-action decisions in loops: If the algorithm decides "do nothing" for 4900 of 5000 symbols, that's 4900 useless …
- Very specific: line 40
Default to Log. Reach for the others only when their specific behavior is needed: Debug / Error for a *handful* of events per day you want …
- Very specific: line 117
If the if checks three things, log all three.
- Distinctive: line 130
Use it for verbose diagnostics you'd only need *if* something went wrong in live — backtests stay clean, and when an incident happens the …
- Very specific: line 134
Put the *why* on the order's tag= rather than a separate log line — it travels with the order, shows on the ticket and trade list, and …
- Very specific: line 178
No logging at all in live: When something goes wrong you'll have nothing to diagnose against.
“Common” is measured: kept by at least 6 in 10 of the 20 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Logging in QuantConnect / LEAN
The default mode of an algorithm is silent. Logs are quota-bounded with a silent failure: once the budget runs out, no further lines are written — including the lines you'd actually need when something breaks. This skill is about keeping log volume low enough that the diagnostic trail survives the run.
Quotas (and why every line costs)
| Tier | Logs per backtest | Logs per day |
| Free | 10 KB | 3 MB |
| Quant Researcher | 100 KB | 3 MB |
| Team | 1 MB | 10 MB |
| Trading Firm | 5 MB | 50 MB |
| Institution | ∞ | ∞ |
Daily quotas restore on a 24-hour rolling window, not at midnight, and deleting a backtest or project does not refund the quota. On Free / Quant Researcher tiers, a chatty algorithm on minute or tick resolution can fill the per-backtest budget in a few simulated days. Live trading has its own limit: 100,000 lines per project, retained for up to one year.
Six rules for keeping logs useful
- Only log significant events — trades executed, errors, major state changes (warm-up finished, signal flipped, scheduled rebalance fired). If a reader of the log would skim past the line, it shouldn't be there.
- Never log routine HOLD / no-action decisions in loops. If the algorithm decides "do nothing" for 4900 of 5000 symbols, that's 4900 useless lines per bar. Log only the active subset, or one summary count.
- Use summary logging. Once per day, write one line listing only the active positions and their P&L. Don't write a status line per bar.
- Avoid logging inside tight loops or per iteration. Aggregate inside the loop, emit one line after.
- Log at key decision points, not every evaluation. The values that led to a decision are useful; every intermediate computation is noise.
- Keep logs actionable and signal-focused. "Sold 100 SPY at 612.34 on EMA cross down" is actionable. "Bar received, EMA=608.11" is not — it tells you nothing the algorithm did.
The four logging functions
Log("My log message");
Debug("My debug message");
Error("My error message");
Quit("My quit message"); // follow with `return;` — Quit schedules a stop but the method keeps runningDefault to Log. Reach for the others only when their specific behavior is needed: Debug / Error for a handful of events per day you want to see live in the Cloud Terminal, Quit only on unrecoverable state.
Patterns
Log on events, not on bars
A logger in OnData writes ~390 lines per simulated trading day at minute resolution. Move it to OnOrderEvent (or another event handler) so it fires only when something happened:
public override void OnOrderEvent(OrderEvent orderEvent)
{
if (orderEvent.Status == OrderStatus.Filled)
{
Log($"{Time}: filled {orderEvent.Symbol} qty={orderEvent.FillQuantity} @ {orderEvent.FillPrice:F2}");
}
}Aggregate inside loops; log once after
A per-symbol log inside the rebalance loop is N lines per rebalance — for a 5000-symbol universe, that's 5000 lines. Compute first, log a summary outside the loop:
var targets = selected.Select(s => (Symbol: s, Weight: ComputeWeight(s))).ToList();
var top = targets.OrderByDescending(t => Math.Abs(t.Weight)).Take(5).ToList();
Log($"{Time}: rebalanced {targets.Count}, top: [{string.Join(\", \", top)}]");
foreach (var (s, w) in targets) SetHoldings(s, w);Daily summary — only the active positions
OnEndOfDay fires once per traded symbol per day, so a universe of 5000 symbols would call it 5000 times. Drive the summary from a Scheduled Event instead — once per trading day, at a time outside any data bar (5 minutes after the US Equity close works on every resolution; see the scheduled-events skill for the rules).
public override void Initialize()
{
Schedule.On(DateRules.EveryDay("SPY"), TimeRules.At(16, 5), DailySummary);
}
private void DailySummary()
{
var active = Portfolio.Where(kvp => kvp.Value.Invested).ToList();
Log($"{Time.Date:yyyy-MM-dd}: {active.Count} positions, total ${Portfolio.TotalPortfolioValue:F2}");
foreach (var kvp in active)
{
Log($" {kvp.Key}: qty={kvp.Value.Quantity} unrealized={kvp.Value.UnrealizedProfit:F2}");
}
}The summary records the useful state — only positions actually held, not zeroes for every symbol in the universe.
End-of-algorithm summary
OnEndOfAlgorithm fires exactly once. Put final stats here.
public override void OnEndOfAlgorithm()
{
Log($"Final portfolio value: {Portfolio.TotalPortfolioValue:F2}");
Log($"Wins: {_wins}, losses: {_losses}");
}Log values before the branch, not after
The point of a diagnostic log is to answer "why did (or didn't) this branch fire?" — which requires logging the inputs before the if, regardless of outcome. Logging only inside the taken branch tells you nothing about the cases where it wasn't.
// Good — log every term in the condition before the if.
SafeLog($"{Time}: close={bar.Close:F2} ema={_ema.Current.Value:F2} qty={Portfolio[_spy].Quantity}");
if (bar.Close > _ema.Current.Value && Portfolio[_spy].Quantity == 0)
{
SetHoldings(_spy, 1);
}If the if checks three things, log all three. When an order doesn't happen, the line shows which term blocked it.
safe_log wrapper for live-only diagnostics
In live trading the volume is naturally capped by wall-clock time, so chatty diagnostics that would blow the backtest quota are fine. Route them through a wrapper that's a no-op in backtests:
private void SafeLog(string message)
{
if (LiveMode) Log(message);
}Use it for verbose diagnostics you'd only need if something went wrong in live — backtests stay clean, and when an incident happens the log already contains the trail.
Prefer order tags over a log call after the order
Put the why on the order's tag= rather than a separate log line — it travels with the order, shows on the ticket and trade list, and costs nothing against the log quota. Include the values that drove the decision, not just a label.
MarketOrder("SPY", 1, tag: $"{Time}: close={bar.Close:F2} ema={_ema.Current.Value:F2}");Object Store for structured Research data
For structured rows you'll analyze in a Research notebook (e.g. a CSV of every signal evaluation), the log file is the wrong tool — size-capped and awkward to parse. Accumulate rows in memory and save once in OnEndOfAlgorithm:
public override void Initialize()
{
_content = "time,symbol,price,tag\n";
}
public override void OnOrderEvent(OrderEvent orderEvent)
{
if (orderEvent.Status == OrderStatus.Filled)
_content += $"{orderEvent.UtcTime},{orderEvent.Symbol},{orderEvent.FillPrice},{orderEvent.Ticket.Tag}\n";
}
public override void OnEndOfAlgorithm()
{
ObjectStore.Save($"{ProjectId}-{AlgorithmId}.txt", _content);
}Read back in Research with qb.ObjectStore.Read(key). Use a stable, unique key like {project_id}-{algorithm_id}.txt so runs don't clobber each other. Save only rows the algorithm derives, such as fills and signals; request price, quote and alternative data again with a history call (see the data-export skill). Backtests only — in live, the 100K-line log file is the right place for diagnostics.
Silent footgun: duplicate-message suppression
If you log the exact same string more than once, only the first call is written — the rest are dropped silently. A per-bar log like Log("Portfolio value below threshold") looks fine on bar one and then disappears. Always include a changing value (timestamp, price, symbol) so each line is distinct:
Log($"{Time}: portfolio below threshold ({Portfolio.TotalPortfolioValue:F2})");Embedding the actual value being logged usually makes the message unique on its own, removing the need for an explicit timestamp.
Common mistakes
- Logging raw market data (bars, trades, quotes from subscribed datasets). Not permitted and the highest-volume content possible. Log the derived quantity (signal value, portfolio value, decision).
- End-of-run state logged from
OnData— belongs inOnEndOfAlgorithmso it fires exactly once. - No logging at all in live. When something goes wrong you'll have nothing to diagnose against. Always log fills and key state transitions; route verbose diagnostics through
safe_log. Debug/ErrorfromOnDataon minute/tick data. Rate-limited to ~1/second, so most calls vanish. For high-frequency diagnostics uselog; reservedebug/errorfor a handful of notable events per day.Quitwithout a followingreturn. The algorithm will stop, but the current method keeps executing until it returns naturally; orders placed after the quit call still go through.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

