cc-os/plugins/os-context/eval/fixture/project/bin/gen-logs

140 lines
4.6 KiB
Ruby
Executable File

#!/usr/bin/env ruby
# frozen_string_literal: true
# Deterministic sample-log generator for the Relaystation eval fixture.
# Produces relay-*.log and worker-*.log files under logs/ (default: the
# project root next to this script, or ARGV[0] if given). No Random, no
# Time.now — every byte of output is a pure function of loop indices, so
# running this script twice produces byte-identical files.
TARGET_DIR = ARGV[0] || File.expand_path('..', __dir__)
LOGS_DIR = File.join(TARGET_DIR, 'logs')
Dir.mkdir(LOGS_DIR) unless Dir.exist?(LOGS_DIR)
DAYS = %w[2026-07-01 2026-07-02 2026-07-03 2026-07-04].freeze
TENANTS = %w[acme globex initech umbrella soylent].freeze
SERVICES = %w[billing crm analytics email sms audit search webhooks reports].freeze
WORKERS = %w[worker-1 worker-2 worker-3 worker-4 worker-5].freeze
STEP_MS = 180
TOTAL_LINES = 760
def timestamp(date, index)
total_ms = index * STEP_MS
total_seconds = total_ms / 1000
ms = total_ms % 1000
hh = (total_seconds / 3600) % 24
mm = (total_seconds / 60) % 60
ss = total_seconds % 60
format('%s %02d:%02d:%02d.%03d', date, hh, mm, ss, ms)
end
def event_id(index)
format('evt_%04d', index % 10_000)
end
def fmt_line(date, index, level, component, message)
"#{timestamp(date, index)} #{level} [#{component}] #{message}\n"
end
def routine_relay_line(date, index)
tenant = TENANTS[index % TENANTS.length]
service = SERVICES[index % SERVICES.length]
case index % 4
when 0
fmt_line(date, index, 'INFO', 'ingest', "event #{event_id(index)} accepted from tenant #{tenant}")
when 1
fmt_line(date, index, 'INFO', 'dispatch', "event #{event_id(index)} delivered to service #{service}")
when 2
fmt_line(date, index, 'INFO', 'auth', "signature verified for tenant #{tenant}")
else
fmt_line(date, index, 'DEBUG', 'metrics', "events.ingested=#{index}")
end
end
def routine_worker_line(date, index)
worker = WORKERS[index % WORKERS.length]
case index % 3
when 0
fmt_line(date, index, 'INFO', 'worker', "#{worker} processed #{event_id(index)} in #{(index % 40) + 5}ms")
when 1
fmt_line(date, index, 'DEBUG', 'heartbeat', "#{worker} heartbeat ok")
else
fmt_line(date, index, 'INFO', 'scaler', "pool size stable at #{WORKERS.length} workers")
end
end
def write_relay_log(date, incident)
path = File.join(LOGS_DIR, "relay-#{date}.log")
File.open(path, 'w') do |f|
(0...TOTAL_LINES).each do |index|
f.write(incident.call(date, index) || routine_relay_line(date, index))
end
end
end
def write_worker_log(date, incident)
path = File.join(LOGS_DIR, "worker-#{date}.log")
File.open(path, 'w') do |f|
(0...TOTAL_LINES).each do |index|
f.write(incident.call(date, index) || routine_worker_line(date, index))
end
end
end
no_incident = ->(_date, _index) { nil }
# 2026-07-01 — routine traffic, no incidents.
write_relay_log('2026-07-01', no_incident)
write_worker_log('2026-07-01', no_incident)
# 2026-07-02 — relay: auth token expiry causes a 401 retry storm.
# worker: normal.
auth_storm = lambda do |date, index|
next nil unless index >= 400 && index < 640
offset = index - 400
case offset % 3
when 0
fmt_line(date, index, 'WARN', 'auth', 'signature token expired for tenant acme')
when 1
fmt_line(date, index, 'ERROR', 'dispatch', 'upstream responded 401')
else
attempt = ((offset / 3) % 8) + 1
fmt_line(date, index, 'INFO', 'retry', "scheduling retry (attempt #{attempt}) after 401")
end
end
write_relay_log('2026-07-02', auth_storm)
write_worker_log('2026-07-02', no_incident)
# 2026-07-03 — routine traffic, no incidents.
write_relay_log('2026-07-03', no_incident)
write_worker_log('2026-07-03', no_incident)
# 2026-07-04 — worker-3 dies, capacity drops, queue fills, events are
# dropped. Worker heartbeat misses begin shortly before the relay's queue
# depth escalation starts.
worker_death = lambda do |date, index|
if index >= 550 && index < 660 && (index - 550) % 20 == 0
fmt_line(date, index, 'WARN', 'heartbeat', 'worker-3 heartbeat missed')
elsif index == 660
fmt_line(date, index, 'ERROR', 'worker', 'worker-3 marked dead')
end
end
write_worker_log('2026-07-04', worker_death)
queue_backup = lambda do |date, index|
if index >= 600 && index < 700
step = index - 600
depth = 100 + (step * 4900 / 99)
depth = 5000 if depth > 5000
fmt_line(date, index, 'WARN', 'queue', "queue depth #{depth}")
elsif index >= 700
fmt_line(date, index, 'ERROR', 'dispatch', "DROPPED event #{event_id(index)} (queue full)")
end
end
write_relay_log('2026-07-04', queue_backup)
puts "wrote #{DAYS.length * 2} log files to #{LOGS_DIR}"