moonlogfmt-lens

Parse, contract-check, redact, profile, and diff logfmt data in MoonBit

logfmt
logs
schema
redaction
drift
moonbit
moon add sqhyyy/moonlogfmt-lens@0.2.1
Download zip
Author
Version
0.2.1
License
Apache-2.0
Last updated
18 days ago
Downloads
4
README

#MoonLogfmt Lens

MoonLogfmt Lens is a MoonBit-native data-contract and quality toolkit for logfmt records. It parses existing log text, classifies semantic values, checks executable contracts, removes sensitive data, profiles batches, and explains schema drift without introducing a logging framework or telemetry stack.

The package is designed for CI pipelines, command-line tools, support bundles, build logs, and service diagnostics. It has no external runtime dependencies and keeps all analysis deterministic across MoonBit targets.

#Why This Exists

Human-readable key/value logs are easy to emit but difficult to govern. Duplicate keys can hide values, a field can silently change from an integer to text, newly added fields can leak credentials, and one release can drift away from the schema observed in the previous release.

MoonLogfmt Lens answers five separate questions:

  • Is the record syntactically valid and unambiguous?
  • Do its fields satisfy an executable log contract?
  • Does it contain credentials, personal data, payment data, or network identity?
  • What value-free shapes and semantic types occur in a batch?
  • Did the current batch drift materially from a known-good baseline?

#Install

moon add sqhyyy/moonlogfmt-lens

The public repository is prepared for sqhyyy/moonlogfmt-lens, and the Mooncakes owner is sqhyyy.

#Parse And Audit

let parsed = @lens.parse(
"level=info msg=\"service ready\" request_id=req-42",
)

if parsed.is_valid() {
println(parsed.get("msg"))
println(parsed.normalized())
}

let audit = @lens.audit_line_with_policy(
"level=warn msg=one msg=two dry_run",
@lens.AuditPolicy::ci(),
)
println(audit.text_report())

The scanner supports bare values, quoted values, common escapes, explicit blank values, and flag fields. It preserves field order and offsets and reports malformed keys, unexpected equals signs, bare quotes, and unterminated strings.

#Semantic Values

inspect(@lens.classify_value("503"), content="ValueInteger")
inspect(@lens.classify_value("1.5s"), content="ValueDuration")
inspect(@lens.classify_value("2026-07-29T12:30:00Z"), content="ValueTimestamp")

The deterministic classifier recognizes flags, blanks, booleans, integers, decimals, durations, byte sizes, timestamps, IPv4 values, UUIDs, email addresses, hexadecimal values, identifiers, and free text. These types form the shared vocabulary used by contract inference and drift analysis.

#Executable Contracts

let contract = @lens.LogContract::new(
"api-service",
[
@lens.FieldRule::typed("level", @lens.ValueIdentifier, required=true)
.with_allowed_values(["info", "warn", "error"]),
@lens.FieldRule::text("msg", required=true).with_max_length(240),
@lens.FieldRule::typed("status", @lens.ValueInteger),
@lens.FieldRule::typed("duration", @lens.ValueDuration),
],
unknown_fields=@lens.UnknownReject,
)

let report = @lens.validate_contract(
"level=info msg=ready status=200 duration=12ms",
contract,
)
println(report.decision())

Contracts support required fields, semantic types, blank/flag controls, maximum lengths, controlled vocabularies, record field limits, duplicate rejection, and allow/warn/reject policies for unknown fields. Built-in service and CI contracts are available for quick adoption.

#Schema Inference

let inference = @lens.infer_schema([
"level=info status=200 duration=12ms",
"level=warn status=503 duration=1.5s",
"level=info status=201 duration=9ms",
])

println(inference.text_report())
let candidate = inference.contract()

Inference reports field prevalence, type distribution, dominant type, confidence, distinct sample values, and observed maximum length. It produces a candidate contract while limiting enum inference to genuinely categorical fields such as level, environment, state, and outcome.

#Privacy-Safe Logs

let result = @lens.redact_line(
"level=info email=user@example.com api_token=secret peer=10.0.0.8",
policy=@lens.RedactionPolicy::strict(),
)

println(result.safe_line())
println(result.json_report())

Privacy analysis combines key-aware rules with value-aware detection for bearer credentials, provider access keys, three-segment tokens, private-key markers, email addresses, formatted phone numbers, checksum-valid payment cards, high-entropy secrets, and optional IP-address protection.

Redaction modes include full masking, last-four masking, and deterministic stable tokens. Reports never serialize the original sensitive value.

#Batch Profiles

let batch = @lens.analyze_batch(
[
"level=info msg=ready status=200",
"level=warn msg=slow status=503",
],
policy=@lens.BatchPolicy::ci(),
)

let decision = @lens.evaluate_batch(
batch,
policy=@lens.BatchGatePolicy::ci(),
)
println(decision.label())

Batch analysis provides valid/invalid rates, risk bands, aggregate scores, field profiles, and value-free structural clusters. Canonical shapes are independent of field order, and stable fingerprints allow logs to be compared without retaining their concrete values.

Batch gates support invalid-line budgets, high-risk budgets, average risk limits, shape-cardinality limits, and required-key prevalence.

#Drift Detection

let baseline = @lens.analyze_batch([
"level=info msg=ready status=200 duration=12ms",
"level=warn msg=slow status=503 duration=80ms",
])

let current = @lens.analyze_batch([
"level=info msg=ready status=ok region=us",
"level=warn msg=slow status=failed region=eu",
])

let drift = @lens.compare_batches(
baseline,
current,
policy=@lens.DriftPolicy::ci(),
)
println(drift.text_report())

Drift findings cover added and removed fields, semantic type changes, type confidence drops, prevalence changes, value-length growth, new and retired shapes, invalid-rate regressions, and aggregate-risk regressions. A known-good batch can also be frozen into a reusable LogContract.

#CLI

moon run cmd/main -- audit level=info msg="service ready" moon run cmd/main -- contract level=info msg=ready service=api moon run cmd/main -- privacy level=info api_token=secret moon run cmd/main -- profile status=503 duration=12ms moon run cmd/main -- template level=info msg=ready status=200

Omitting the mode keeps compatibility with the original audit command.

#Runnable Examples

moon run examples/basic moon run examples/advanced moon run examples/privacy moon run examples/drift

The advanced example infers and freezes a baseline contract. The privacy example demonstrates stable-token redaction. The drift example intentionally introduces a field-type regression, a removed field, a new field, a new shape, and malformed input.

#Verification

moon fmt moon check moon build moon test moon package --list

The current suite contains 95 tests covering parsing, auditing, semantic classification, contracts, inference, redaction, batch gates, structural fingerprints, and drift reports.

#Boundaries

MoonLogfmt Lens consumes in-memory logfmt records. It does not emit application logs, tail files, collect telemetry, export OpenTelemetry data, parse JSON, or replace logging frameworks. File readers, network collectors, and dashboards can build on top of the dependency-free core.

#Contributing

Development and verification instructions are available in CONTRIBUTING.md.

#License

Apache-2.0.

#
AuditPolicy

pub struct AuditPolicy {
max_fields : Int
max_value_length : Int
flag_duplicate_keys : Bool
flag_blank_values : Bool
flag_flag_fields : Bool
required_keys : Array[String]
} derive(
Debug
)

#
AuditPolicy::ci

#
AuditPolicy::default

fn AuditPolicy::default() -> AuditPolicy

#
AuditPolicy::relaxed

fn AuditPolicy::relaxed() -> AuditPolicy

#
AuditPolicy::with_required_keys

fn AuditPolicy::with_required_keys(self : AuditPolicy, keys : Array[String]) -> AuditPolicy

#
AuditReport

pub struct AuditReport {
parsed : ParseResult
findings : Array[Finding]
} derive(
Debug
)

#
AuditReport::count_severity

fn AuditReport::count_severity(self : AuditReport, severity : Severity) -> Int

#
AuditReport::critical_count

fn AuditReport::critical_count(self : AuditReport) -> Int

#
AuditReport::finding_count

fn AuditReport::finding_count(self : AuditReport) -> Int

#
AuditReport::findings

fn AuditReport::findings(self : AuditReport) -> Array[Finding]

#
AuditReport::info_count

fn AuditReport::info_count(self : AuditReport) -> Int

#
AuditReport::json_report

fn AuditReport::json_report(self : AuditReport) -> String

#
AuditReport::parsed

fn AuditReport::parsed(self : AuditReport) -> ParseResult

#
AuditReport::recommended_action

fn AuditReport::recommended_action(self : AuditReport) -> String

#
AuditReport::risk_level

fn AuditReport::risk_level(self : AuditReport) -> String

#
AuditReport::risk_score

fn AuditReport::risk_score(self : AuditReport) -> Int

#
AuditReport::text_report

fn AuditReport::text_report(self : AuditReport) -> String

#
AuditReport::warning_count

fn AuditReport::warning_count(self : AuditReport) -> Int

#
BatchDecision

pub struct BatchDecision {
accepted : Bool
reasons : Array[String]
} derive(Eq,
Debug
)

#
BatchDecision::accepted

fn BatchDecision::accepted(self : BatchDecision) -> Bool

#
BatchDecision::label

fn BatchDecision::label(self : BatchDecision) -> String

#
BatchDecision::reasons

fn BatchDecision::reasons(self : BatchDecision) -> Array[String]

#
BatchDecision::text_report

fn BatchDecision::text_report(self : BatchDecision) -> String

#
BatchGatePolicy

pub struct BatchGatePolicy {
max_invalid_percent : Int
max_high_risk_percent : Int
max_average_risk_score : Int
reject_shape_overflow : Bool
required_keys : Array[String]
min_required_prevalence : Int
} derive(Eq,
Debug
)

#
BatchGatePolicy::ci

#
BatchGatePolicy::default

#
BatchGatePolicy::with_error_budget

fn BatchGatePolicy::with_error_budget(self : BatchGatePolicy, max_invalid_percent : Int, max_high_risk_percent : Int) -> BatchGatePolicy

#
BatchGatePolicy::with_required_keys

fn BatchGatePolicy::with_required_keys(self : BatchGatePolicy, required_keys : Array[String], min_prevalence? : Int) -> BatchGatePolicy

#
BatchPolicy

pub struct BatchPolicy {
audit_policy : AuditPolicy
skip_blank_lines : Bool
max_distinct_shapes : Int
} derive(
Debug
)

Controls batch analysis without introducing file-system or process I/O.

#
BatchPolicy::ci

#
BatchPolicy::default

fn BatchPolicy::default() -> BatchPolicy

#
BatchPolicy::exploratory

fn BatchPolicy::exploratory() -> BatchPolicy

#
BatchPolicy::with_audit_policy

fn BatchPolicy::with_audit_policy(self : BatchPolicy, audit_policy : AuditPolicy) -> BatchPolicy

#
BatchPolicy::with_blank_lines

fn BatchPolicy::with_blank_lines(self : BatchPolicy, skip_blank_lines : Bool) -> BatchPolicy

#
BatchPolicy::with_shape_limit

fn BatchPolicy::with_shape_limit(self : BatchPolicy, max_distinct_shapes : Int) -> BatchPolicy

#
BatchReport

pub struct BatchReport {
input_lines : Int
processed_lines : Int
skipped_blank_lines : Int
valid_lines : Int
invalid_lines : Int
clean_lines : Int
low_risk_lines : Int
medium_risk_lines : Int
high_risk_lines : Int
aggregate_risk_score : Int
reviews : Array[LineReview]
profiles : Array[FieldProfile]
shapes : Array[ShapeStat]
shape_limit_exceeded : Bool
} derive(
Debug
)

#
BatchReport::aggregate_risk_score

fn BatchReport::aggregate_risk_score(self : BatchReport) -> Int

#
BatchReport::average_risk_score

fn BatchReport::average_risk_score(self : BatchReport) -> Int

#
BatchReport::clean_lines

fn BatchReport::clean_lines(self : BatchReport) -> Int

#
BatchReport::high_risk_lines

fn BatchReport::high_risk_lines(self : BatchReport) -> Int

#
BatchReport::high_risk_percent

fn BatchReport::high_risk_percent(self : BatchReport) -> Int

#
BatchReport::input_lines

fn BatchReport::input_lines(self : BatchReport) -> Int

#
BatchReport::invalid_lines

fn BatchReport::invalid_lines(self : BatchReport) -> Int

#
BatchReport::invalid_percent

fn BatchReport::invalid_percent(self : BatchReport) -> Int

#
BatchReport::json_report

fn BatchReport::json_report(self : BatchReport) -> String

#
BatchReport::low_risk_lines

fn BatchReport::low_risk_lines(self : BatchReport) -> Int

#
BatchReport::medium_risk_lines

fn BatchReport::medium_risk_lines(self : BatchReport) -> Int

#
BatchReport::most_common_shape

fn BatchReport::most_common_shape(self : BatchReport) -> ShapeStat?

#
BatchReport::processed_lines

fn BatchReport::processed_lines(self : BatchReport) -> Int

#
BatchReport::profile_for

fn BatchReport::profile_for(self : BatchReport, key : String) -> FieldProfile?

#
BatchReport::profiles

fn BatchReport::profiles(self : BatchReport) -> Array[FieldProfile]

#
BatchReport::reviews

fn BatchReport::reviews(self : BatchReport) -> Array[LineReview]

#
BatchReport::shape_count

fn BatchReport::shape_count(self : BatchReport) -> Int

#
BatchReport::shape_for_fingerprint

fn BatchReport::shape_for_fingerprint(self : BatchReport, fingerprint : String) -> ShapeStat?

#
BatchReport::shape_limit_exceeded

fn BatchReport::shape_limit_exceeded(self : BatchReport) -> Bool

#
BatchReport::shapes

fn BatchReport::shapes(self : BatchReport) -> Array[ShapeStat]

#
BatchReport::skipped_blank_lines

fn BatchReport::skipped_blank_lines(self : BatchReport) -> Int

#
BatchReport::text_report

fn BatchReport::text_report(self : BatchReport) -> String

#
BatchReport::valid_lines

fn BatchReport::valid_lines(self : BatchReport) -> Int

#
ContractReport

pub struct ContractReport {
contract_name : String
parsed : ParseResult
violations : Array[ContractViolation]
} derive(
Debug
)

#
ContractReport::contract_name

fn ContractReport::contract_name(self : ContractReport) -> String

#
ContractReport::critical_count

fn ContractReport::critical_count(self : ContractReport) -> Int

#
ContractReport::decision

fn ContractReport::decision(self : ContractReport) -> String

#
ContractReport::is_conformant

fn ContractReport::is_conformant(self : ContractReport) -> Bool

#
ContractReport::json_report

fn ContractReport::json_report(self : ContractReport) -> String

#
ContractReport::parsed

#
ContractReport::text_report

fn ContractReport::text_report(self : ContractReport) -> String

#
ContractReport::violation_count

fn ContractReport::violation_count(self : ContractReport) -> Int

#
ContractReport::violations

#
ContractReport::warning_count

fn ContractReport::warning_count(self : ContractReport) -> Int

#
ContractViolation

pub struct ContractViolation {
kind : ContractViolationKind
severity : Severity
key : String
expected : String
actual : String
message : String
offset : Int
} derive(Eq,
Debug
)

#
ContractViolation::actual

fn ContractViolation::actual(self : ContractViolation) -> String

#
ContractViolation::expected

fn ContractViolation::expected(self : ContractViolation) -> String

#
ContractViolation::key

fn ContractViolation::key(self : ContractViolation) -> String

#
ContractViolation::kind

#
ContractViolation::message

fn ContractViolation::message(self : ContractViolation) -> String

#
ContractViolation::offset

fn ContractViolation::offset(self : ContractViolation) -> Int

#
ContractViolation::severity

#
ContractViolationKind

pub(all) enum ContractViolationKind {
ContractSyntaxError
ContractMissingField
ContractUnexpectedField
ContractWrongType
ContractBlankDisallowed
ContractFlagDisallowed
ContractValueTooLong
ContractValueNotAllowed
ContractDuplicateField
ContractFieldLimit
} derive(Eq,
Debug
)

#
ContractViolationKind::label

fn ContractViolationKind::label(self : ContractViolationKind) -> String

#
DriftFinding

pub struct DriftFinding {
kind : DriftKind
severity : Severity
subject : String
baseline : String
current : String
message : String
} derive(Eq,
Debug
)

#
DriftFinding::baseline

fn DriftFinding::baseline(self : DriftFinding) -> String

#
DriftFinding::current

fn DriftFinding::current(self : DriftFinding) -> String

#
DriftFinding::kind

fn DriftFinding::kind(self : DriftFinding) -> DriftKind

#
DriftFinding::message

fn DriftFinding::message(self : DriftFinding) -> String

#
DriftFinding::severity

fn DriftFinding::severity(self : DriftFinding) -> Severity

#
DriftFinding::subject

fn DriftFinding::subject(self : DriftFinding) -> String

#
DriftKind

pub(all) enum DriftKind {
DriftAddedField
DriftRemovedField
DriftTypeChanged
DriftTypeConfidenceDrop
DriftPrevalenceIncrease
DriftPrevalenceDecrease
DriftValueLengthGrowth
DriftNewShape
DriftRetiredShape
DriftInvalidRateIncrease
DriftRiskIncrease
} derive(Eq,
Debug
)

Explainable changes detected between two logfmt batches.

#
DriftKind::label

fn DriftKind::label(self : DriftKind) -> String

#
DriftPolicy

pub struct DriftPolicy {
prevalence_delta : Int
confidence_drop : Int
max_length_growth : Int
invalid_rate_delta : Int
average_risk_delta : Int
min_field_prevalence : Int
report_retired_shapes : Bool
} derive(Eq,
Debug
)

#
DriftPolicy::ci

#
DriftPolicy::default

fn DriftPolicy::default() -> DriftPolicy

#
DriftPolicy::exploratory

fn DriftPolicy::exploratory() -> DriftPolicy

#
DriftPolicy::with_invalid_budget

fn DriftPolicy::with_invalid_budget(self : DriftPolicy, invalid_rate_delta : Int) -> DriftPolicy

#
DriftPolicy::with_prevalence_delta

fn DriftPolicy::with_prevalence_delta(self : DriftPolicy, prevalence_delta : Int) -> DriftPolicy

#
DriftPolicy::with_retired_shapes

fn DriftPolicy::with_retired_shapes(self : DriftPolicy, report_retired_shapes : Bool) -> DriftPolicy

#
DriftReport

pub struct DriftReport {
baseline_lines : Int
current_lines : Int
findings : Array[DriftFinding]
} derive(Eq,
Debug
)

#
DriftReport::baseline_lines

fn DriftReport::baseline_lines(self : DriftReport) -> Int

#
DriftReport::critical_count

fn DriftReport::critical_count(self : DriftReport) -> Int

#
DriftReport::current_lines

fn DriftReport::current_lines(self : DriftReport) -> Int

#
DriftReport::decision

fn DriftReport::decision(self : DriftReport) -> String

#
DriftReport::finding_count

fn DriftReport::finding_count(self : DriftReport) -> Int

#
DriftReport::findings

fn DriftReport::findings(self : DriftReport) -> Array[DriftFinding]

#
DriftReport::json_report

fn DriftReport::json_report(self : DriftReport) -> String

#
DriftReport::risk_score

fn DriftReport::risk_score(self : DriftReport) -> Int

#
DriftReport::text_report

fn DriftReport::text_report(self : DriftReport) -> String

#
DriftReport::warning_count

fn DriftReport::warning_count(self : DriftReport) -> Int

#
Field

pub struct Field {
key : String
value : String
quoted : Bool
flag : Bool
offset : Int
} derive(Eq,
Debug
)

One parsed logfmt field.

#
Field::is_flag

fn Field::is_flag(self : Field) -> Bool

#
Field::key

fn Field::key(self : Field) -> String

#
Field::new

fn Field::new(key : String, value : String, quoted? : Bool, flag? : Bool, offset? : Int) -> Field

#
Field::offset

fn Field::offset(self : Field) -> Int

#
Field::pair

fn Field::pair(self : Field) -> String

#
Field::quoted

fn Field::quoted(self : Field) -> Bool

#
Field::value

fn Field::value(self : Field) -> String

#
FieldProfile

pub struct FieldProfile {
key : String
lines_seen : Int
values_seen : Int
max_length : Int
distinct_values : Array[String]
distribution : ValueDistribution
} derive(Eq,
Debug
)

#
FieldProfile::distinct_values

fn FieldProfile::distinct_values(self : FieldProfile) -> Array[String]

#
FieldProfile::distribution

fn FieldProfile::distribution(self : FieldProfile) -> ValueDistribution

#
FieldProfile::dominant_kind

fn FieldProfile::dominant_kind(self : FieldProfile) -> ValueKind

#
FieldProfile::key

fn FieldProfile::key(self : FieldProfile) -> String

#
FieldProfile::lines_seen

fn FieldProfile::lines_seen(self : FieldProfile) -> Int

#
FieldProfile::max_length

fn FieldProfile::max_length(self : FieldProfile) -> Int

#
FieldProfile::prevalence_percent

fn FieldProfile::prevalence_percent(self : FieldProfile, valid_lines : Int) -> Int

#
FieldProfile::summary

fn FieldProfile::summary(self : FieldProfile, valid_lines : Int) -> String

#
FieldProfile::type_confidence

fn FieldProfile::type_confidence(self : FieldProfile) -> Int

#
FieldProfile::values_seen

fn FieldProfile::values_seen(self : FieldProfile) -> Int

#
FieldRule

pub struct FieldRule {
key : String
expected_kind : ValueKind
required : Bool
allow_blank : Bool
allow_flag : Bool
max_length : Int
allowed_values : Array[String]
} derive(Eq,
Debug
)

One executable field rule in a log contract.

#
FieldRule::allowed_values

fn FieldRule::allowed_values(self : FieldRule) -> Array[String]

#
FieldRule::allows_blank

fn FieldRule::allows_blank(self : FieldRule) -> Bool

#
FieldRule::allows_flag

fn FieldRule::allows_flag(self : FieldRule) -> Bool

#
FieldRule::describe

fn FieldRule::describe(self : FieldRule) -> String

#
FieldRule::expected_kind

fn FieldRule::expected_kind(self : FieldRule) -> ValueKind

#
FieldRule::key

fn FieldRule::key(self : FieldRule) -> String

#
FieldRule::max_length

fn FieldRule::max_length(self : FieldRule) -> Int

#
FieldRule::required

fn FieldRule::required(self : FieldRule) -> Bool

#
FieldRule::text

fn FieldRule::text(key : String, required? : Bool) -> FieldRule

#
FieldRule::typed

fn FieldRule::typed(key : String, expected_kind : ValueKind, required? : Bool) -> FieldRule

#
FieldRule::with_allowed_values

fn FieldRule::with_allowed_values(self : FieldRule, allowed_values : Array[String]) -> FieldRule

#
FieldRule::with_blank

fn FieldRule::with_blank(self : FieldRule, allow_blank : Bool) -> FieldRule

#
FieldRule::with_flag

fn FieldRule::with_flag(self : FieldRule, allow_flag : Bool) -> FieldRule

#
FieldRule::with_max_length

fn FieldRule::with_max_length(self : FieldRule, max_length : Int) -> FieldRule

#
FieldRule::with_required

fn FieldRule::with_required(self : FieldRule, required : Bool) -> FieldRule

#
Finding

pub struct Finding {
kind : FindingKind
severity : Severity
key : String
message : String
offset : Int
} derive(Eq,
Debug
)

#
Finding::key

fn Finding::key(self : Finding) -> String

#
Finding::kind

fn Finding::kind(self : Finding) -> FindingKind

#
Finding::message

fn Finding::message(self : Finding) -> String

#
Finding::new

fn Finding::new(kind : FindingKind, severity : Severity, key : String, message : String, offset? : Int) -> Finding

#
Finding::offset

fn Finding::offset(self : Finding) -> Int

#
Finding::severity

fn Finding::severity(self : Finding) -> Severity

#
FindingKind

pub(all) enum FindingKind {
SyntaxError
DuplicateKey
RequiredKeyMissing
TooManyFields
ValueTooLong
BlankValue
FlagField
ControlCharacter
} derive(Eq,
Debug
)

Audit finding kinds for logfmt quality and CI review.

#
FindingKind::label

fn FindingKind::label(self : FindingKind) -> String

#
InferencePolicy

pub struct InferencePolicy {
required_percent : Int
type_confidence_percent : Int
enum_cardinality_limit : Int
unknown_fields : UnknownFieldPolicy
} derive(Eq,
Debug
)

#
InferencePolicy::default

#
InferencePolicy::enum_cardinality_limit

fn InferencePolicy::enum_cardinality_limit(self : InferencePolicy) -> Int

#
InferencePolicy::exploratory

fn InferencePolicy::exploratory() -> InferencePolicy

#
InferencePolicy::required_percent

fn InferencePolicy::required_percent(self : InferencePolicy) -> Int

#
InferencePolicy::strict

#
InferencePolicy::type_confidence_percent

fn InferencePolicy::type_confidence_percent(self : InferencePolicy) -> Int

#
LineReview

pub struct LineReview {
line_number : Int
shape : String
fingerprint : String
report : AuditReport
} derive(
Debug
)

Per-line analysis intentionally omits the original source text.

#
LineReview::fingerprint

fn LineReview::fingerprint(self : LineReview) -> String

#
LineReview::is_valid

fn LineReview::is_valid(self : LineReview) -> Bool

#
LineReview::line_number

fn LineReview::line_number(self : LineReview) -> Int

#
LineReview::report

fn LineReview::report(self : LineReview) -> AuditReport

#
LineReview::risk_level

fn LineReview::risk_level(self : LineReview) -> String

#
LineReview::shape

fn LineReview::shape(self : LineReview) -> String

#
LogContract

pub struct LogContract {
name : String
rules : Array[FieldRule]
unknown_fields : UnknownFieldPolicy
max_fields : Int
} derive(
Debug
)

A named, executable schema for logfmt records.

#
LogContract::ci_event

fn LogContract::ci_event() -> LogContract

A compact contract suited to build and CI logs.

#
LogContract::describe

fn LogContract::describe(self : LogContract) -> String

#
LogContract::has_rule

fn LogContract::has_rule(self : LogContract, key : String) -> Bool

#
LogContract::max_fields

fn LogContract::max_fields(self : LogContract) -> Int

#
LogContract::name

fn LogContract::name(self : LogContract) -> String

#
LogContract::new

fn LogContract::new(name : String, rules : Array[FieldRule], unknown_fields? : UnknownFieldPolicy, max_fields? : Int) -> LogContract

#
LogContract::required_count

fn LogContract::required_count(self : LogContract) -> Int

#
LogContract::rule_count

fn LogContract::rule_count(self : LogContract) -> Int

#
LogContract::rules

fn LogContract::rules(self : LogContract) -> Array[FieldRule]

#
LogContract::service

fn LogContract::service() -> LogContract

A practical contract for ordinary service logs.

#
LogContract::unknown_field_policy

fn LogContract::unknown_field_policy(self : LogContract) -> UnknownFieldPolicy

#
ParseError

pub struct ParseError {
kind : ParseErrorKind
message : String
offset : Int
} derive(Eq,
Debug
)

#
ParseError::kind

#
ParseError::message

fn ParseError::message(self : ParseError) -> String

#
ParseError::offset

fn ParseError::offset(self : ParseError) -> Int

#
ParseErrorKind

pub(all) enum ParseErrorKind {
EmptyKey
InvalidKey
UnexpectedEquals
UnterminatedQuote
BareQuote
} derive(Eq,
Debug
)

Syntax problems found while parsing one logfmt line.

#
ParseErrorKind::label

fn ParseErrorKind::label(self : ParseErrorKind) -> String

#
ParseResult

pub struct ParseResult {
source : String
fields : Array[Field]
errors : Array[ParseError]
} derive(
Debug
)

#
ParseResult::error_count

fn ParseResult::error_count(self : ParseResult) -> Int

#
ParseResult::errors

fn ParseResult::errors(self : ParseResult) -> Array[ParseError]

#
ParseResult::field_count

fn ParseResult::field_count(self : ParseResult) -> Int

#
ParseResult::fields

fn ParseResult::fields(self : ParseResult) -> Array[Field]

#
ParseResult::get

fn ParseResult::get(self : ParseResult, key : String) -> String

#
ParseResult::has_key

fn ParseResult::has_key(self : ParseResult, key : String) -> Bool

#
ParseResult::is_valid

fn ParseResult::is_valid(self : ParseResult) -> Bool

#
ParseResult::normalized

fn ParseResult::normalized(self : ParseResult) -> String

#
ParseResult::source

fn ParseResult::source(self : ParseResult) -> String

#
ParseResult::summary

fn ParseResult::summary(self : ParseResult) -> String

#
PrivacyFinding

pub struct PrivacyFinding {
key : String
kind : SensitiveKind
reason : String
offset : Int
} derive(Eq,
Debug
)

#
PrivacyFinding::key

fn PrivacyFinding::key(self : PrivacyFinding) -> String

#
PrivacyFinding::kind

#
PrivacyFinding::offset

fn PrivacyFinding::offset(self : PrivacyFinding) -> Int

#
PrivacyFinding::reason

fn PrivacyFinding::reason(self : PrivacyFinding) -> String

#
PrivacyFinding::severity

fn PrivacyFinding::severity(self : PrivacyFinding) -> Severity

#
RedactionMode

pub(all) enum RedactionMode {
RedactFull
RedactKeepLastFour
RedactStableToken
} derive(Eq,
Debug
)

How a sensitive value should be represented in safe output.

#
RedactionMode::label

fn RedactionMode::label(self : RedactionMode) -> String

#
RedactionPolicy

pub struct RedactionPolicy {
mode : RedactionMode
secret_key_fragments : Array[String]
personal_key_fragments : Array[String]
payment_key_fragments : Array[String]
network_key_fragments : Array[String]
allow_keys : Array[String]
detect_values : Bool
redact_network_values : Bool
} derive(
Debug
)

Privacy rules for key-aware and value-aware redaction.

#
RedactionPolicy::default

#
RedactionPolicy::key_only

#
RedactionPolicy::mode

#
RedactionPolicy::strict

#
RedactionPolicy::with_allow_keys

fn RedactionPolicy::with_allow_keys(self : RedactionPolicy, allow_keys : Array[String]) -> RedactionPolicy

#
RedactionPolicy::with_mode

#
RedactionPolicy::with_network_values

fn RedactionPolicy::with_network_values(self : RedactionPolicy, redact_network_values : Bool) -> RedactionPolicy

#
RedactionPolicy::with_value_detection

fn RedactionPolicy::with_value_detection(self : RedactionPolicy, detect_values : Bool) -> RedactionPolicy

#
RedactionResult

pub struct RedactionResult {
parsed : ParseResult
safe_line : String
findings : Array[PrivacyFinding]
redacted_keys : Array[String]
} derive(
Debug
)

The privacy-safe projection of one parsed line.

Reports never include the original sensitive values. The original source is retained only through the parsed result for in-process callers and is not serialized by the report methods.

#
RedactionResult::critical_count

fn RedactionResult::critical_count(self : RedactionResult) -> Int

#
RedactionResult::decision

fn RedactionResult::decision(self : RedactionResult) -> String

#
RedactionResult::finding_count

fn RedactionResult::finding_count(self : RedactionResult) -> Int

#
RedactionResult::findings

#
RedactionResult::is_safe

fn RedactionResult::is_safe(self : RedactionResult) -> Bool

#
RedactionResult::json_report

fn RedactionResult::json_report(self : RedactionResult) -> String

#
RedactionResult::parsed

#
RedactionResult::redacted_count

fn RedactionResult::redacted_count(self : RedactionResult) -> Int

#
RedactionResult::redacted_keys

fn RedactionResult::redacted_keys(self : RedactionResult) -> Array[String]

#
RedactionResult::safe_line

fn RedactionResult::safe_line(self : RedactionResult) -> String

#
RedactionResult::text_report

fn RedactionResult::text_report(self : RedactionResult) -> String

#
SchemaInference

pub struct SchemaInference {
total_lines : Int
valid_lines : Int
invalid_lines : Int
profiles : Array[FieldProfile]
contract : LogContract
} derive(
Debug
)

#
SchemaInference::contract

#
SchemaInference::invalid_lines

fn SchemaInference::invalid_lines(self : SchemaInference) -> Int

#
SchemaInference::json_report

fn SchemaInference::json_report(self : SchemaInference) -> String

#
SchemaInference::profile_for

fn SchemaInference::profile_for(self : SchemaInference, key : String) -> FieldProfile?

#
SchemaInference::profiles

#
SchemaInference::text_report

fn SchemaInference::text_report(self : SchemaInference) -> String

#
SchemaInference::total_lines

fn SchemaInference::total_lines(self : SchemaInference) -> Int

#
SchemaInference::valid_lines

fn SchemaInference::valid_lines(self : SchemaInference) -> Int

#
SensitiveKind

pub(all) enum SensitiveKind {
SensitiveSecret
SensitiveCredential
SensitivePersonal
SensitivePayment
SensitiveNetwork
} derive(Eq,
Debug
)

Categories used by the privacy scanner.

#
SensitiveKind::label

fn SensitiveKind::label(self : SensitiveKind) -> String

#
SensitiveKind::severity

fn SensitiveKind::severity(self : SensitiveKind) -> Severity

#
Severity

pub(all) enum Severity {
Info
Warning
Critical
} derive(Eq,
Debug
)

Severity assigned to an audit finding.

#
Severity::label

fn Severity::label(self : Severity) -> String

#
Severity::score

fn Severity::score(self : Severity) -> Int

#
ShapeStat

pub struct ShapeStat {
shape : String
fingerprint : String
count : Int
first_line : Int
} derive(Eq,
Debug
)

A value-free structural cluster. Shape strings contain only field names, semantic kinds, and flag markers.

#
ShapeStat::count

fn ShapeStat::count(self : ShapeStat) -> Int

#
ShapeStat::fingerprint

fn ShapeStat::fingerprint(self : ShapeStat) -> String

#
ShapeStat::first_line

fn ShapeStat::first_line(self : ShapeStat) -> Int

#
ShapeStat::shape

fn ShapeStat::shape(self : ShapeStat) -> String

#
ShapeStat::summary

fn ShapeStat::summary(self : ShapeStat) -> String

#
UnknownFieldPolicy

pub(all) enum UnknownFieldPolicy {
UnknownAllow
UnknownWarn
UnknownReject
} derive(Eq,
Debug
)

Policy used when a contract encounters a key it does not declare.

#
UnknownFieldPolicy::label

fn UnknownFieldPolicy::label(self : UnknownFieldPolicy) -> String

#
ValueDistribution

pub struct ValueDistribution {
flag_count : Int
empty_count : Int
boolean_count : Int
integer_count : Int
decimal_count : Int
duration_count : Int
byte_size_count : Int
timestamp_count : Int
ipv4_count : Int
uuid_count : Int
email_count : Int
hex_count : Int
identifier_count : Int
text_count : Int
} derive(Eq,
Debug
)

A compact distribution of value kinds.

#
ValueDistribution::count

fn ValueDistribution::count(self : ValueDistribution, kind : ValueKind) -> Int

#
ValueDistribution::distinct_kind_count

fn ValueDistribution::distinct_kind_count(self : ValueDistribution) -> Int

#
ValueDistribution::dominant_kind

fn ValueDistribution::dominant_kind(self : ValueDistribution) -> ValueKind

#
ValueDistribution::dominant_percent

fn ValueDistribution::dominant_percent(self : ValueDistribution) -> Int

#
ValueDistribution::empty

#
ValueDistribution::summary

fn ValueDistribution::summary(self : ValueDistribution) -> String

#
ValueDistribution::total

fn ValueDistribution::total(self : ValueDistribution) -> Int

#
ValueDistribution::with_kind

#
ValueKind

pub(all) enum ValueKind {
ValueFlag
ValueEmpty
ValueBoolean
ValueInteger
ValueDecimal
ValueDuration
ValueByteSize
ValueTimestamp
ValueIPv4
ValueUuid
ValueEmail
ValueHex
ValueIdentifier
ValueText
} derive(Eq,
Debug
)

Semantic value families recognized by MoonLogfmt Lens.

The classifier is intentionally deterministic and dependency-free. It does not try to replace a full date, network, or identity parser. Its purpose is to give contract inference and drift analysis a stable vocabulary.

#
ValueKind::accepts

fn ValueKind::accepts(self : ValueKind, actual : ValueKind) -> Bool

Returns true when values of actual are accepted by a rule for expected.

Integer values are accepted by decimal rules, while every value can be represented as text. Empty and flag values remain explicit so callers can decide whether they are allowed.

#
ValueKind::label

fn ValueKind::label(self : ValueKind) -> String

#
analyze_batch

fn analyze_batch(lines : Array[String], policy? : BatchPolicy) -> BatchReport

#
audit

fn audit(parsed : ParseResult, policy : AuditPolicy) -> AuditReport

#
audit_line

fn audit_line(line : String) -> AuditReport

#
audit_line_with_policy

fn audit_line_with_policy(line : String, policy : AuditPolicy) -> AuditReport

#
classify_field

fn classify_field(field : Field) -> ValueKind

Classifies a parsed field while preserving the distinction between an implicit flag and an explicit boolean value.

#
classify_value

fn classify_value(value : String) -> ValueKind

Classifies one logfmt value using a stable, ordered set of recognizers.

#
compare_batches

fn compare_batches(baseline : BatchReport, current : BatchReport, policy? : DriftPolicy) -> DriftReport

#
contract_from_batch

fn contract_from_batch(report : BatchReport, name? : String, required_percent? : Int, unknown_fields? : UnknownFieldPolicy) -> LogContract

Freezes a reusable contract from a previously analyzed baseline.

#
evaluate_batch

fn evaluate_batch(report : BatchReport, policy? : BatchGatePolicy) -> BatchDecision

#
infer_schema

fn infer_schema(lines : Array[String], policy? : InferencePolicy) -> SchemaInference

#
is_valid

fn is_valid(line : String) -> Bool

#
parse

fn parse(line : String) -> ParseResult

#
profile_values

fn profile_values(values : Array[String]) -> ValueDistribution

#
redact_line

fn redact_line(line : String, policy? : RedactionPolicy) -> RedactionResult

#
redact_parsed

fn redact_parsed(parsed : ParseResult, policy : RedactionPolicy) -> RedactionResult

#
scan_privacy

fn scan_privacy(line : String) -> RedactionResult

Scans without changing policy defaults. The returned safe line can be used directly in diagnostics, fixtures, or support bundles.

#
shape_fingerprint

fn shape_fingerprint(shape : String) -> String

Stable, non-cryptographic identifier for a value-free structural shape.

#
structural_shape

fn structural_shape(parsed : ParseResult) -> String

Returns a canonical shape independent of field order and field values.

#
structural_template

fn structural_template(line : String) -> String

Returns a value-free template in original field order.

#
validate_contract

fn validate_contract(line : String, contract : LogContract) -> ContractReport

#
validate_parsed_contract

fn validate_parsed_contract(parsed : ParseResult, contract : LogContract) -> ContractReport