This folder contains YAML schemas that declaratively define each log source and its events. A generator turns these schemas into Sorbet-typed Ruby T::Structs under lib/log_struct/log/*, plus supporting helpers.
- Inputs: YAML files in
schemas/log_sources/*.ymland the meta JSON Schemas inschemas/meta/*. - Enums: Human-friendly field names are defined in
lib/log_struct/enums/log_field.rb(e.g.,Database,DurationMs). Each enum value serializes to a compact JSON key (e.g.,:db,:duration_ms). - Validation: The meta schema
schemas/meta/log-source-schema.jsonvalidates every source schema. It importsschemas/meta/log-fields.json, an auto-generated enum of allowedLogFieldnames for field keys. - Codegen: Run
ruby scripts/generate_structs.rbto:- Generate Ruby structs for every source/event
- Rebuild
schemas/meta/log-fields.jsonfromLogFieldso schema validation stays in sync
- schemas/log_sources/*.yml: One file per source. Declares base fields and events.
- schemas/meta/log-source-schema.json: JSON Schema for validating the shape and field names of all source YAMLs.
- schemas/meta/log-fields.json: Generated from
LogField; lists the only allowed field key names. - scripts/generate_structs.rb: Main codegen entry; generates Ruby + TS and log-fields.
- LogField meta schema is generated as part of
scripts/generate_structs.rb(from theLogFieldenum).
- source: Required. CamelCase source name, e.g.,
ActiveJob,SQL. - snake_case: Optional snake-case filename override; normally inferred.
- consts.source: Optional override for the
Sourceenum; omit unless it differs from source name. - additional_data: Boolean. If true, generated structs include an
additional_dataHash merged at top-level on serialization. - add_request_fields: Boolean. Adds request-related accessors and merges them during serialization.
- base.default_required: Optional boolean, true by default. Set it to false to make base fields optional, with per-field
required: truefor exceptions. - base.fields: Map of
LogFieldnames to types.
-
events: Map of event name → object with keys:
- default_required: Optional boolean, true by default. Set it to false to make event fields optional, with per-field
required: truefor exceptions. - fields: Map of
LogFieldnames to types. Field keys must be validLogFieldenum names (validated bylog-fields.json).
- default_required: Optional boolean, true by default. Set it to false to make event fields optional, with per-field
-
You may also declare an event with no fields by using a bare event key or
null:Delivery:orDelivery: null→ generates an event with no additional fields.
You can write fields in two styles:
-
Shorthand (recommended):
FieldName: Type- Required determined by
default_required(event/base). - Example:
DurationMs: Float
- Required determined by
-
Object form: Use when a field's requirement differs from
default_required:Message: type: String required: false
- Use the exact
LogFieldconstant name for keys (e.g.,RequestId,Database,DurationMs,WaitMs). - The generator maps these to short JSON keys via
LogField(e.g.,RequestId→:req_id).
- Durations: Prefer explicit units. Use
DurationMsfor durations in milliseconds. UseWaitMsfor wait times in milliseconds. - Optional data: Use
additional_data: trueonly when needed; the generator flattens the hash on serialization. - Source override: Omit
consts.sourceunless the source enum differs from the source name.
- Single-event sources generate a single top-level struct (e.g.,
LogStruct::Log::Request). - Multi-event sources generate:
- A parent file
lib/log_struct/log/<source>.rbthat requires event files and may defineBaseFields. - One file per event (e.g.,
lib/log_struct/log/<source>/<event>.rb).
- A parent file
- All generated classes:
- Include shared common fields (source, event, timestamp, level)
- Serialize using
LogField::<Name>.serializefor every key - Serialize
Timefields as ISO-8601 strings - Respect
default_requiredandrequiredfor field nilability
- Use
default_required: falsewhen all fields in an event (or base) are optional — this removes per-fieldrequired: falsenoise. - Do NOT add
default_required: falsewhen you have a mix of required and optional fields — declare required fields in shorthand and optional fields withrequired: false.
Examples:
All optional fields:
default_required: false
fields:
Filename: String
MimeType: StringMixed required and optional fields:
fields:
Message: String
AhoyEvent:
type: String
required: false- Validate schemas:
bundle exec ruby -Itest test/schemas/schema_validation_test.rb - Generate structs + log-fields:
ruby scripts/generate_structs.rb
- Using snake_case field keys. Always use
LogFieldnames (e.g.,RequestId, notrequest_id). - Adding
default_required: falseto events that have a mix of required and optional fields — this turns everything optional. Instead, omit it and mark optional fields explicitly. - Hardcoding JSON keys. Generated code always uses
LogField::<Name>.serializefor keys.