
Usage Logging
- 95 installs
- 325 repo stars
- Updated August 2, 2026
- athola/claude-night-market
Standardize JSONL usage logs for agent sessions—tokens, duration, success, and rich metadata—so you can jq-query cost and failure patterns later.
About
usage-logging (documented as log-formats in SKILL.md) is a reference skill for structured agent and service usage telemetry written as JSONL. Solo builders running Claude Night Market–style automations use it when every shell or API invocation should leave a comparable audit trail: ISO timestamps, session identifiers, operation names, token counts, boolean success, durations, and optional metadata blocks tuned for file batches or model calls. The skill is not a logger implementation—it prescribes schemas and bash/jq patterns so you can grep a day, compute success ratios, or surface expensive operations without inventing a new format per project. It pairs naturally with grow-phase analytics and operate-phase incident review when failures spike. Install it when you are about to wire hooks or scripts that emit usage.jsonl and want agents to append consistent fields rather than ad-hoc printf lines.
- Standard JSONL entry fields: timestamp, session_id, service, operation, tokens, success, duration_seconds, metadata
- Dedicated error entry shape with error_type and error_message when success is false
- Metadata patterns for file ops (files_processed, total_bytes, file_types) and API ops (model, input_tokens, output_token
- jq query recipes for time range, success rate, failures-only, high-token ops, and token sums
Usage Logging by the numbers
- 95 all-time installs (skills.sh)
- Ranked #4,606 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/athola/claude-night-market --skill usage-loggingAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 95 |
|---|---|
| repo stars | ★ 325 |
| Security audit | 2 / 3 scanners passed |
| Last updated | August 2, 2026 |
| Repository | athola/claude-night-market ↗ |
What it does
Standardize JSONL usage logs for agent sessions—tokens, duration, success, and rich metadata—so you can jq-query cost and failure patterns later.
Files
Table of Contents
- Overview
- When to Use
- Core Concepts
- Session Management
- Log Entry Structure
- Quick Start
- Initialize Logger
- Log Operations
- Query Usage
- Integration Pattern
- Log Storage
- Detailed Resources
- Exit Criteria
Usage Logging
Overview
Session-aware logging infrastructure for tracking operations across plugins. Provides structured JSONL logging with automatic session management for audit trails and analytics.
When To Use
- Need audit trails for operations
- Tracking costs across sessions
- Building usage analytics
- Debugging with operation history
When NOT To Use
- Simple operations without logging needs
Core Concepts
Session Management
Sessions group related operations:
- Auto-created on first operation
- Timeout after 1 hour of inactivity
- Unique session IDs for tracking
Log Entry Structure
{
"timestamp": "2025-12-05T10:30:00Z",
"session_id": "session_1733394600",
"service": "my-service",
"operation": "analyze_files",
"tokens": 5000,
"success": true,
"duration_seconds": 2.5,
"metadata": {}
}Verification: Run the command with --help flag to verify availability.
Quick Start
Initialize Logger
from leyline.usage_logger import UsageLogger
logger = UsageLogger(service="my-service")Verification: Run the command with --help flag to verify availability.
Log Operations
logger.log_usage(
operation="analyze_files",
tokens=5000,
success=True,
duration=2.5,
metadata={"files": 10}
)Verification: Run the command with --help flag to verify availability.
Query Usage
# Recent operations
recent = logger.get_recent_operations(hours=24)
# Usage summary
summary = logger.get_usage_summary(days=7)
print(f"Total tokens: {summary['total_tokens']}")
print(f"Total cost: ${summary['estimated_cost']:.2f}")
# Recent errors
errors = logger.get_recent_errors(count=10)Verification: Run the command with --help flag to verify availability.
Integration Pattern
# In your skill's frontmatter
dependencies: [leyline:usage-logging]Verification: Run the command with --help flag to verify availability.
Standard integration flow: 1. Initialize logger for your service 2. Log operations after completion 3. Query for analytics and debugging
Log Storage
Default location: ~/.claude/leyline/usage/{service}.jsonl
# View recent logs
tail -20 ~/.claude/leyline/usage/my-service.jsonl | jq .
# Query by date
grep "2025-12-05" ~/.claude/leyline/usage/my-service.jsonlVerification: Run the command with --help flag to verify availability.
Detailed Resources
- Session Patterns: See
modules/session-patterns.mdfor session management - Log Formats: See
modules/log-formats.mdfor structured formats
Exit Criteria
- Operation logged with all required fields
- Session tracked for grouping
- Logs queryable for analytics
Log Formats
JSONL Schema
Standard Entry
{
"timestamp": "ISO-8601 datetime",
"session_id": "session_UNIX_TIMESTAMP",
"service": "service-name",
"operation": "operation-name",
"tokens": 0,
"success": true,
"duration_seconds": 0.0,
"metadata": {}
}Error Entry
{
"timestamp": "ISO-8601 datetime",
"session_id": "session_xxx",
"service": "service-name",
"operation": "operation-name",
"tokens": 0,
"success": false,
"error_type": "RateLimitError",
"error_message": "Rate limit exceeded",
"duration_seconds": 0.5
}Metadata Patterns
File Operations
{
"metadata": {
"files_processed": 10,
"total_bytes": 50000,
"file_types": [".py", ".md"]
}
}API Operations
{
"metadata": {
"model": "gemini-2.5-pro",
"input_tokens": 5000,
"output_tokens": 1000,
"temperature": 0.7
}
}Query Patterns
By Time Range
# Last 24 hours
jq 'select(.timestamp > "2025-12-04")' usage.jsonl
# Specific date
grep "2025-12-05" usage.jsonl | jq .By Success/Failure
# Failures only
jq 'select(.success == false)' usage.jsonl
# Success rate
jq -s '[.[] | .success] | add / length' usage.jsonlBy Token Usage
# High token operations
jq 'select(.tokens > 10000)' usage.jsonl
# Total tokens
jq -s '[.[] | .tokens] | add' usage.jsonlSession Patterns
Session Lifecycle
Creation
def _get_or_create_session(self) -> str:
"""Get existing session or create new one."""
session_file = self.log_dir / "session.json"
if session_file.exists():
session = json.loads(session_file.read_text())
# Check if session is still active (1 hour timeout)
if time.time() - session["last_activity"] < 3600:
return session["session_id"]
# Create new session
session_id = f"session_{int(time.time())}"
session_file.write_text(json.dumps({
"session_id": session_id,
"created_at": time.time(),
"last_activity": time.time()
}))
return session_idActivity Tracking
def _update_session_activity(self):
"""Update session last activity timestamp."""
session_file = self.log_dir / "session.json"
if session_file.exists():
session = json.loads(session_file.read_text())
session["last_activity"] = time.time()
session_file.write_text(json.dumps(session))Session Grouping
Query by Session
def get_session_operations(self, session_id: str) -> list[dict]:
"""Get all operations for a session."""
operations = []
for line in self.log_file.read_text().splitlines():
entry = json.loads(line)
if entry.get("session_id") == session_id:
operations.append(entry)
return operationsSession Statistics
def get_session_stats(self, session_id: str) -> dict:
"""Get statistics for a session."""
ops = self.get_session_operations(session_id)
return {
"operation_count": len(ops),
"total_tokens": sum(o.get("tokens", 0) for o in ops),
"success_rate": sum(1 for o in ops if o["success"]) / len(ops),
"total_duration": sum(o.get("duration_seconds", 0) for o in ops)
}Cross-Service Sessions
Shared Session IDs
When operations span multiple services:
# Pass session_id between services
logger1 = UsageLogger(service="gemini", session_id=shared_session)
logger2 = UsageLogger(service="qwen", session_id=shared_session)Session Correlation
def correlate_sessions(loggers: list[UsageLogger]) -> dict:
"""Correlate operations across services in same session."""
all_ops = []
for logger in loggers:
all_ops.extend(logger.get_recent_operations(hours=1))
# Sort by timestamp
all_ops.sort(key=lambda x: x["timestamp"])
return all_opsRelated skills
FAQ
Is Usage Logging safe to install?
skills.sh reports 2 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.