Skip to content

Commit 50a0946

Browse files
committed
added dotenv-rails integration
1 parent eb81198 commit 50a0946

37 files changed

Lines changed: 903 additions & 251 deletions

.cspell/project-words.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ carrierwave
1111
creds
1212
dalli
1313
docspring
14+
dotenv
15+
Dotenv
1416
Fanout
1517
favicons
1618
gettime
@@ -19,6 +21,7 @@ Healthcheck
1921
Honeybadger
2022
hotwire
2123
hrefs
24+
instrumenter
2225
kamal
2326
klass
2427
kwargs
@@ -28,6 +31,7 @@ logdev
2831
Logstop
2932
LogStruct
3033
metaprogramming
34+
mswin
3135
nilable
3236
optparse
3337
parseable

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
/plans
1414
/log
1515

16+
# Source code references
17+
/reference
18+
1619
# Next.js site ignore rules are in ./site/.gitignore
1720

1821
# CSpell generated wordlists (from package lockfiles)

AGENTS.md

Lines changed: 126 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,126 @@
1-
Read CLAUDE.md for instructions
1+
# LogStruct Development Guide
2+
3+
## 🚨 CRITICAL RULES - MUST ALWAYS BE FOLLOWED 🚨
4+
5+
1. **NEVER mark a feature as done until `./scripts/all_check.sh` is passing**
6+
2. **ALWAYS run `./scripts/all_check.sh` before claiming completion**
7+
3. **NO EXCEPTIONS to the above rules - features are NOT complete until all checks pass**
8+
4. **This rule must ALWAYS be followed no matter what**
9+
10+
## Commands
11+
12+
### Core Commands
13+
14+
- Setup: `scripts/setup.sh`
15+
- Run all checks: `scripts/all_check.sh` (runs typecheck, export, lint, test, etc.)
16+
- Run all checks with auto-fix: `scripts/all_write.sh`
17+
- Interactive console: `scripts/console.rb`
18+
19+
### Testing Commands
20+
21+
- Run all tests (unit + Rails integration): `scripts/all_tests.sh`
22+
- Run all Ruby unit tests: `scripts/test.rb`
23+
- Run single test file: `scripts/test.rb test/path_to_test.rb`
24+
- Run test at specific line: `scripts/test.rb test/path_to_test.rb:LINE_NUMBER`
25+
- Run test by name: `scripts/test.rb -n=test_method_name`
26+
- Debug a specific test: Add `debugger` statements (developer only)
27+
- Run Rails integration tests: `scripts/rails_tests.sh`
28+
- Merge coverage reports: `scripts/merge_coverage.sh`
29+
- Run Next.js TypeScript tests: `cd site && npm test`
30+
31+
### Quality Commands
32+
33+
- Ruby typecheck: `scripts/typecheck.sh`
34+
- Next.js typecheck: `cd site && pnpm exec tsc --noEmit`
35+
- Lint Ruby: `scripts/rubocop.rb`
36+
- Format Ruby: `scripts/rubocop.rb -A`
37+
- Format JS/TS/JSON: `scripts/prettier.sh --write`
38+
- Lint JS/TS/JSON: `scripts/prettier.sh --check`
39+
- Spellcheck: `scripts/spellcheck.sh`
40+
41+
### Development Commands
42+
43+
- Generate Sorbet RBI files: `scripts/tapioca.rb`
44+
- Generate spellcheck dictionary: `scripts/generate_lockfile_words.sh`
45+
- Generate TypeScript types from Ruby log structs: `scripts/export_typescript_types.rb`
46+
47+
## Terraform Provider repo in this workspace
48+
49+
- The Terraform provider lives in a separate GitHub repo: `DocSpring/terraform-provider-logstruct`.
50+
- For convenience, the provider repo is checked out as a plain directory at `./terraform-provider-logstruct/` in this repo. It is NOT a Git submodule and is ignored by this repo’s `.gitignore`.
51+
- You can inspect/build it locally:
52+
- `cd terraform-provider-logstruct`
53+
- `go build ./...`
54+
- Changes you make here are not committed by this repo. To contribute to the provider, commit from inside its directory and push to its own remote.
55+
56+
## Automated releases (gem + provider)
57+
58+
- Workflow: `.github/workflows/release.yml` ("Release Gem + Sync Terraform Provider").
59+
- Triggers:
60+
- Push tag matching `v*` (e.g., `v0.0.1-rc1`, `v0.2.0`).
61+
- GitHub Release published.
62+
- Manual run (workflow_dispatch) with `dry_run` input.
63+
- Behavior:
64+
- Builds and publishes the Ruby gem to RubyGems (requires `RUBYGEMS_API_KEY`).
65+
- Regenerates the provider’s embedded catalog (`scripts/export_provider_catalog.rb`), builds the provider, commits catalog changes, and tags the provider repo with the same version.
66+
- Enforces version alignment: the tag `vX.Y.Z` (or RC) must match `lib/log_struct/version.rb` unless run in dry-run.
67+
68+
## Dry-run mode
69+
70+
- CI dry-run lets you smoke-test the workflow without publishing anything:
71+
- Actions → "Release Gem + Sync Terraform Provider" → Run workflow → `dry_run=true`.
72+
- The workflow builds the gem and provider, shows diffs, and skips pushes/tags/uploads.
73+
- Local dry-run for the GitHub Actions workflow isn’t practical without a runner like `act`. You can still sanity-check pieces locally:
74+
- `gem build logstruct.gemspec`
75+
- `ruby scripts/export_typescript_types.rb`
76+
- `ruby scripts/export_provider_catalog.rb`
77+
- `cd terraform-provider-logstruct && go build ./...`
78+
79+
## Required secrets
80+
81+
- `RUBYGEMS_API_KEY`: API key with permission to publish `logstruct`.
82+
- `PROVIDER_PUSH_TOKEN`: PAT with write access to `DocSpring/terraform-provider-logstruct` for syncing/tagging.
83+
84+
# Core Dependencies
85+
86+
This gem requires Rails 7.0+ and will always have access to these core Rails modules:
87+
88+
- `::Rails`
89+
- `::ActiveSupport`
90+
- `::ActionDispatch`
91+
- `::ActionController`
92+
93+
You do not need to check if these are defined with `defined?` - they are guaranteed to be available.
94+
95+
## Code Style
96+
97+
- NEVER add comments about what you changed (e.g. "this was moved", or "more performant".)
98+
- NEVER worry about backwards compatibility. This is all brand new code, you must delete old methods and files after refactoring, don't keep them for compatibility.
99+
- Use strict Sorbet typing with `# typed: strict` annotations
100+
- You can use `# typed: true` in tests
101+
- Method signatures must include proper return types
102+
- Use `::` prefixes for external modules (Rails/third-party gems)
103+
- `T.must` may be used very sparingly but only in tests - e.g. `T.must(log_file.path)`
104+
- `T.unsafe` must NEVER be used. Use proper typing or `T.let`/`T.cast` when necessary
105+
- Don't call `def` inside a method definition in tests (or anywhere). Use mocks or stubs.
106+
- For modules included in other classes, use `requires_ancestor`
107+
- Custom type overrides belong in `sorbet/rbi/overrides/`
108+
- Follow standard Ruby naming conventions:
109+
- Classes: `CamelCase`
110+
- Methods/variables: `snake_case`
111+
- Boolean methods should end with `?`
112+
- Handle errors explicitly via type-safe interfaces
113+
- NEVER ignore warnings (especially deprecation warnings) - keep the logs clean
114+
- When handling objects with as_json method in Rails apps, consider whether ActiveSupport's default implementation or a custom implementation is being used
115+
- Use minitest mocks and stubs, not `def`, `Object`, etc.
116+
117+
## Code Comments
118+
119+
- Comments should explain why code exists, not what it does
120+
- Do not reference previous versions/iterations in comments
121+
- When receiving feedback, incorporate it into the code without mentioning the feedback
122+
- Never use words like "proper" or "correctly" in comments as they imply previous code was improper
123+
124+
## Development Standards
125+
126+
THERE IS NO RUSH. There is NEVER any need to hurry through a feature or a fix. There are NO deadlines. Never, ever, ever say anything like "let me quickly implement this" or "for now we'll just do this" or "TODO: we'll fix this later" or ANYTHING along those lines. You are a veteran. A senior engineer. You are the most patient and thorough senior engineer of all time. Your patience is unending and your love of high quality code knows no bounds. You take the utmost care and ensure that your code is engineered to the highest standards of quality. You might need to take a detour and refactor a giant method and clean up code as you go. You might notice that some code has been architected all wrong and you need to rewrite it from scratch. This does not concern you at all. You roll up your sleeves and you do the work. YOU TAKE NO SHORTCUTS. AND YOU ALWAYS WRITE TESTS.

CLAUDE.md

Lines changed: 0 additions & 131 deletions
This file was deleted.

lib/log_struct/boot_buffer.rb

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# typed: strict
2+
# frozen_string_literal: true
3+
4+
module LogStruct
5+
# Collects structured logs during very early boot before the logger is ready.
6+
module BootBuffer
7+
extend T::Sig
8+
9+
@@logs = T.let([], T::Array[LogStruct::Log::Interfaces::CommonFields])
10+
11+
sig { params(log: LogStruct::Log::Interfaces::CommonFields).void }
12+
def self.add(log)
13+
@@logs << log
14+
end
15+
16+
sig { void }
17+
def self.flush
18+
return if @@logs.empty?
19+
@@logs.each { |l| LogStruct.info(l) }
20+
@@logs.clear
21+
end
22+
23+
sig { void }
24+
def self.clear
25+
@@logs.clear
26+
end
27+
end
28+
end

lib/log_struct/concerns/configuration.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,16 @@ def enabled?
4141
def set_enabled_from_rails_env!
4242
# Set enabled based on current Rails environment and the LOGSTRUCT_ENABLED env var.
4343
# Precedence:
44-
# 1. Check if LOGSTRUCT_ENABLED env var is defined
45-
# - Sets enabled=true only when value is "true"
46-
# - Sets enabled=false when value is "false" (or any non-"true")
44+
# 1. Check if LOGSTRUCT_ENABLED env var is defined (not an empty string)
45+
# - Sets enabled=true only when value is "true", "yes", "1", etc.
46+
# - Sets enabled=false when value is any other value
4747
# 2. Otherwise, check if current Rails environment is in enabled_environments
4848
# 3. Otherwise, leave as config.enabled (defaults to true)
4949

5050
# Then check if LOGSTRUCT_ENABLED env var is set
5151
config.enabled = if ENV["LOGSTRUCT_ENABLED"]
5252
# Override to true only if env var is "true"
53-
ENV["LOGSTRUCT_ENABLED"] == "true"
53+
%w[true t yes y 1].include?(ENV["LOGSTRUCT_ENABLED"]&.strip&.downcase)
5454
else
5555
config.enabled_environments.include?(::Rails.env.to_sym)
5656
end

lib/log_struct/concerns/error_handling.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def error_handling_mode_for(source)
2626
when Source::Security
2727
config.error_handling_modes.security_errors
2828
when Source::Rails, Source::App, Source::Job, Source::Storage, Source::Mailer,
29-
Source::Shrine, Source::CarrierWave, Source::Sidekiq
29+
Source::Shrine, Source::CarrierWave, Source::Sidekiq, Source::Dotenv
3030
config.error_handling_modes.standard_errors
3131
else
3232
# Ensures the case statement is exhaustive

lib/log_struct/config_struct/integrations.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ class Integrations < T::Struct
9898
# Enable ActiveModelSerializers integration
9999
# Default: true (safe no-op unless ActiveModelSerializers is defined)
100100
prop :enable_active_model_serializers, T::Boolean, default: true
101+
102+
# Enable dotenv-rails integration (convert to structured logs)
103+
# Default: true
104+
prop :enable_dotenv, T::Boolean, default: true
101105
end
102106
end
103107
end

lib/log_struct/enums/event.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ class Event < T::Enum
3030
Delivery = new(:delivery)
3131
Delivered = new(:delivered)
3232

33+
# Configuration / boot events
34+
Load = new(:load)
35+
Update = new(:update)
36+
Save = new(:save)
37+
Restore = new(:restore)
38+
3339
# Security events
3440
IPSpoof = new(:ip_spoof)
3541
CSRFViolation = new(:csrf_violation)

lib/log_struct/enums/source.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class Source < T::Enum
2222
Shrine = new(:shrine)
2323
CarrierWave = new(:carrierwave)
2424
Sidekiq = new(:sidekiq)
25+
Dotenv = new(:dotenv)
2526
end
2627
end
2728
end

0 commit comments

Comments
 (0)