{"id":51126887,"url":"https://github.com/slbug/julewire","last_synced_at":"2026-06-27T10:00:34.190Z","repository":{"id":366428093,"uuid":"1276199732","full_name":"slbug/julewire","owner":"slbug","description":"Structured logging for modern Ruby: core pipeline, Rails/AJ/Karafka/Ractor adapters, GCP shape, redaction, tail/doctor tools, and contract tests. Sharp edges documented, boundaries enforced, logs that behave under load.","archived":false,"fork":false,"pushed_at":"2026-06-26T08:06:49.000Z","size":639,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-06-26T09:26:27.123Z","etag":null,"topics":["activejob","gcp","karafka","logging","ractors","rails","ruby","ruby-on-rails","semantic-logger","structured-logging"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/slbug.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":"support/mutant/ruby_itblock.rb","governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-21T17:03:27.000Z","updated_at":"2026-06-26T08:06:30.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/slbug/julewire","commit_stats":null,"previous_names":["slbug/julewire"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/slbug/julewire","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slbug%2Fjulewire","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slbug%2Fjulewire/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slbug%2Fjulewire/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slbug%2Fjulewire/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/slbug","download_url":"https://codeload.github.com/slbug/julewire/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slbug%2Fjulewire/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34848932,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-27T02:00:06.362Z","response_time":126,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["activejob","gcp","karafka","logging","ractors","rails","ruby","ruby-on-rails","semantic-logger","structured-logging"],"created_at":"2026-06-25T08:32:18.602Z","updated_at":"2026-06-27T10:00:34.162Z","avatar_url":"https://github.com/slbug.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Julewire\n\nJulewire is an execution-scoped structured logging toolkit for Ruby.\n\nIt is not a logger skin. Core owns record shape, context, propagation,\nprocessors, summaries, health, and synchronous output contracts. Integrations\nmap Rails, Active Job, Karafka, GCP, Semantic Logger, and Ractor edges onto that\ncore without depending on each other.\n\n## TL;DR\n\n```ruby\nJulewire.configure do |config|\n  config.destinations.use(:default, output: $stdout)\nend\n\nJulewire.with_execution(type: :request, id: \"req-1\") do\n  Julewire.context.add(tenant_id: \"acme\")\n  Julewire.summary.increment(:db_queries)\n  Julewire.measure(:render) do\n    Julewire.emit(\"handled\", event: \"orders.show\", order_id: 123)\n  end\nend\n```\n\nRecords are newline JSON by default. Framework gems add request/job/message\nlifecycles, structured events, propagation carriers, and provider formatting.\n\n## Gems\n\n| Gem | Path | Job |\n| --- | --- | --- |\n| `julewire-core` | [gems/core](gems/core) | Runtime, records, context, processors, destinations, contracts. |\n| `julewire-rack` | [gems/rack](gems/rack) | Shared Rack-family request support. |\n| `julewire-rails` | [gems/rails](gems/rails) | Rails logger, request summaries, Rails events, Rails errors. |\n| `julewire-rails_support` | [gems/rails_support](gems/rails_support) | Shared Rails-family support. |\n| `julewire-active_job` | [gems/active_job](gems/active_job) | Job summaries, job events, and propagation through job data. |\n| `julewire-karafka` | [gems/karafka](gems/karafka) | Karafka/WaterDrop events, message context, and Kafka carriers. |\n| `julewire-gcp` | [gems/gcp](gems/gcp) | Google Cloud Logging JSON shape, trace fields, Error Reporting shape. |\n| `julewire-redaction` | [gems/redaction](gems/redaction) | Bounded whole-record redaction processor. |\n| `julewire-semantic_logger` | [gems/semantic_logger](gems/semantic_logger) | Semantic Logger transport bridge. |\n| `julewire-ractor` | [gems/ractor](gems/ractor) | Experimental Ruby 4.0 Ractor bridge. |\n\n## Rails API Stack\n\nThe normal Rails API setup is:\n\n```ruby\ngem \"julewire-rails\"\ngem \"julewire-active_job\"\ngem \"julewire-gcp\"\ngem \"julewire-redaction\"\ngem \"julewire-semantic_logger\"\n```\n\nThen wire one destination and the filtering policy:\n\n```ruby\nJulewire.configure do |config|\n  config.processors.prepend(\n    :rails_parameter_filter,\n    Rails.application.config.filter_parameters\n  )\n\n  config.destinations.use(\n    :semantic_logger,\n    formatter: Julewire::GCP::Formatter.new(project_id: \"my-project\"),\n    io: $stdout\n  )\nend\n```\n\nRails hash event payloads are filtered by Rails before subscribers see them.\nWhole-record filtering for logger payloads and optional captured fields is a\nJulewire processor decision.\n\n## Developer Tools\n\n`julewire tail` renders newline JSON logs as compact console text. Provider gems\ncan register their own decoders, so GCP-shaped Kubernetes logs can be tailed\nwithout core knowing the GCP wire shape:\n\n```sh\nkubectl logs -f deploy/my-app | julewire tail --format gcp --raw-invalid -\n```\n\n`julewire transcode` reads one registered format and writes another:\n\n```sh\nkubectl logs deploy/my-app | julewire transcode --from gcp --to core --raw-invalid -\n```\n\nSee [gems/core/docs/tail.md](gems/core/docs/tail.md) for the full CLI surface.\n\n## Shape\n\nJulewire records are split into field bags:\n\n- `context`: queryable facts copied onto records and summaries; propagates.\n- `carry`: hidden forwarding metadata; propagates.\n- `attributes`: emitted integration/application namespaces.\n- `neutral`: provider-neutral formatter coordination facts.\n- `summary`: final counters, timings, and completion facts.\n- `labels`: operator-safe routing/grouping metadata.\n- `metrics`: numeric measurements such as duration.\n\nThe core serializer bounds depth, arrays, hashes, strings, cycles, invalid\nencoding, non-finite numerics, and exception shapes. It is a safety layer, not a\nprivacy layer; redaction is explicit processor policy.\n\n## Repo\n\nThis is a monorepo with independently-packaged gems under `gems/`. CI is\npath-filtered by gem; Codecov uses per-gem carryforward flags so partial runs do\nnot pretend untouched gems went dark.\n\n## Development\n\nEach gem owns its test task:\n\n```sh\ncd gems/core\nCOVERAGE=true bundle exec rake\n```\n\nThe root `Rakefile` can orchestrate all gem tasks from a Ruby environment with\nthe gem bundles installed. Rails Appraisal suites live in `gems/rails`; the\nRactor gem runs on Ruby 4.0 only.\n\n## License\n\nMIT. Each packaged gem includes its own `LICENSE.txt`; the repository-level\nlicense is [LICENSE.txt](LICENSE.txt).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fslbug%2Fjulewire","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fslbug%2Fjulewire","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fslbug%2Fjulewire/lists"}