miniapm 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +43 -0
  3. data/LICENSE +21 -0
  4. data/README.md +174 -0
  5. data/lib/generators/miniapm/install_generator.rb +27 -0
  6. data/lib/generators/miniapm/templates/README +19 -0
  7. data/lib/generators/miniapm/templates/initializer.rb +60 -0
  8. data/lib/miniapm/configuration.rb +176 -0
  9. data/lib/miniapm/context.rb +138 -0
  10. data/lib/miniapm/error_event.rb +130 -0
  11. data/lib/miniapm/exporters/errors.rb +67 -0
  12. data/lib/miniapm/exporters/otlp.rb +90 -0
  13. data/lib/miniapm/instrumentations/activejob.rb +271 -0
  14. data/lib/miniapm/instrumentations/activerecord.rb +123 -0
  15. data/lib/miniapm/instrumentations/base.rb +61 -0
  16. data/lib/miniapm/instrumentations/cache.rb +85 -0
  17. data/lib/miniapm/instrumentations/http/faraday.rb +112 -0
  18. data/lib/miniapm/instrumentations/http/httparty.rb +84 -0
  19. data/lib/miniapm/instrumentations/http/net_http.rb +99 -0
  20. data/lib/miniapm/instrumentations/rails/controller.rb +129 -0
  21. data/lib/miniapm/instrumentations/rails/railtie.rb +42 -0
  22. data/lib/miniapm/instrumentations/redis/redis.rb +135 -0
  23. data/lib/miniapm/instrumentations/redis/redis_client.rb +116 -0
  24. data/lib/miniapm/instrumentations/registry.rb +90 -0
  25. data/lib/miniapm/instrumentations/search/elasticsearch.rb +121 -0
  26. data/lib/miniapm/instrumentations/search/opensearch.rb +120 -0
  27. data/lib/miniapm/instrumentations/search/searchkick.rb +119 -0
  28. data/lib/miniapm/instrumentations/sidekiq.rb +185 -0
  29. data/lib/miniapm/middleware/error_handler.rb +120 -0
  30. data/lib/miniapm/middleware/rack.rb +103 -0
  31. data/lib/miniapm/span.rb +289 -0
  32. data/lib/miniapm/testing.rb +209 -0
  33. data/lib/miniapm/trace.rb +26 -0
  34. data/lib/miniapm/transport/batch_sender.rb +345 -0
  35. data/lib/miniapm/transport/http.rb +45 -0
  36. data/lib/miniapm/version.rb +5 -0
  37. data/lib/miniapm.rb +184 -0
  38. metadata +183 -0
data/lib/miniapm.rb ADDED
@@ -0,0 +1,184 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "logger"
4
+
5
+ require_relative "miniapm/version"
6
+ require_relative "miniapm/configuration"
7
+ require_relative "miniapm/context"
8
+ require_relative "miniapm/span"
9
+ require_relative "miniapm/trace"
10
+ require_relative "miniapm/error_event"
11
+ require_relative "miniapm/transport/http"
12
+ require_relative "miniapm/transport/batch_sender"
13
+ require_relative "miniapm/exporters/otlp"
14
+ require_relative "miniapm/exporters/errors"
15
+ require_relative "miniapm/middleware/rack"
16
+ require_relative "miniapm/middleware/error_handler"
17
+ require_relative "miniapm/instrumentations/base"
18
+ require_relative "miniapm/instrumentations/registry"
19
+
20
+ module MiniAPM
21
+ class Error < StandardError; end
22
+ class ConfigurationError < Error; end
23
+
24
+ class << self
25
+ attr_writer :configuration
26
+
27
+ def configuration
28
+ @configuration ||= Configuration.new
29
+ end
30
+
31
+ def configure
32
+ yield(configuration)
33
+ start! if configuration.auto_start
34
+ end
35
+
36
+ def start!
37
+ return if @started
38
+
39
+ configuration.validate!
40
+
41
+ @started = true
42
+ Instrumentations::Registry.install_all!
43
+ Transport::BatchSender.start!
44
+ logger.info { "MiniAPM started (service: #{configuration.service_name})" }
45
+ end
46
+
47
+ def stop!
48
+ return unless @started
49
+
50
+ Transport::BatchSender.stop!
51
+ @started = false
52
+ logger.info { "MiniAPM stopped" }
53
+ end
54
+
55
+ def started?
56
+ @started || false
57
+ end
58
+
59
+ def enabled?
60
+ configuration.enabled && started?
61
+ end
62
+
63
+ def logger
64
+ @logger ||= begin
65
+ log = Logger.new($stdout)
66
+ log.level = Logger::INFO
67
+ log.progname = "MiniAPM"
68
+ log
69
+ end
70
+ end
71
+
72
+ attr_writer :logger
73
+
74
+ # Create a span with automatic context management
75
+ # Sampling is decided once per trace and inherited by all child spans
76
+ def span(name, category: :internal, attributes: {})
77
+ return yield(nil) unless enabled?
78
+
79
+ # Check if we're in an existing trace
80
+ current_trace = Context.current_trace
81
+ parent_span = Context.current_span
82
+
83
+ if current_trace
84
+ # We're already in a trace - use its sampled state
85
+ return yield(nil) unless current_trace.sampled?
86
+
87
+ span = if parent_span
88
+ parent_span.create_child(name, category: category, attributes: attributes)
89
+ else
90
+ Span.new(
91
+ name: name,
92
+ category: category,
93
+ trace_id: current_trace.trace_id,
94
+ attributes: attributes
95
+ )
96
+ end
97
+ else
98
+ # Create new trace with sampling decision
99
+ span = Span.new_root(name, category: category, attributes: attributes)
100
+
101
+ # new_root creates a trace - check if it's sampled
102
+ return yield(nil) unless Context.current_trace&.sampled?
103
+ end
104
+
105
+ Context.with_span(span) do
106
+ yield span
107
+ rescue StandardError => e
108
+ span.record_exception(e)
109
+ raise
110
+ ensure
111
+ span.finish
112
+ record_span(span)
113
+ end
114
+ end
115
+
116
+ def record_span(span)
117
+ return unless enabled?
118
+ return unless Context.current_trace&.sampled?
119
+
120
+ span = begin
121
+ configuration.before_send&.call(span) || span
122
+ rescue StandardError => e
123
+ logger.error { "MiniAPM before_send callback error: #{e.class}: #{e.message}" }
124
+ span # Return original span if callback fails
125
+ end
126
+ return unless span
127
+
128
+ Transport::BatchSender.enqueue(:span, span)
129
+ end
130
+
131
+ def record_error(exception, context: {})
132
+ return unless enabled?
133
+ return if ignored_exception?(exception)
134
+
135
+ error_event = ErrorEvent.from_exception(exception, context)
136
+ Transport::BatchSender.enqueue(:error, error_event)
137
+ end
138
+
139
+ def current_trace_id
140
+ Context.current_trace_id
141
+ end
142
+
143
+ def current_span_id
144
+ Context.current_span&.span_id
145
+ end
146
+
147
+ def current_span
148
+ Context.current_span
149
+ end
150
+
151
+ # Force flush all pending data (useful for testing and graceful shutdown)
152
+ def flush!
153
+ Transport::BatchSender.flush!
154
+ end
155
+
156
+ # Get stats about enqueued/sent/dropped data
157
+ def stats
158
+ Transport::BatchSender.stats
159
+ end
160
+
161
+ # Check if MiniAPM can connect to the server
162
+ def healthy?
163
+ return false unless enabled?
164
+
165
+ result = Transport::HTTP.post(
166
+ "#{configuration.endpoint}/health",
167
+ {},
168
+ headers: { "Authorization" => "Bearer #{configuration.api_key}" }
169
+ )
170
+ result[:success]
171
+ rescue StandardError
172
+ false
173
+ end
174
+
175
+ private
176
+
177
+ def ignored_exception?(exception)
178
+ configuration.ignored_exceptions.include?(exception.class.name)
179
+ end
180
+ end
181
+ end
182
+
183
+ # Load Rails integration if Rails is present
184
+ require_relative "miniapm/instrumentations/rails/railtie" if defined?(Rails::Railtie)
metadata ADDED
@@ -0,0 +1,183 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: miniapm
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Chris Hasinski
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-01-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '13.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '13.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.12'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.12'
41
+ - !ruby/object:Gem::Dependency
42
+ name: webmock
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.19'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.19'
55
+ - !ruby/object:Gem::Dependency
56
+ name: vcr
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '6.2'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '6.2'
69
+ - !ruby/object:Gem::Dependency
70
+ name: timecop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.9'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.9'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rack
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rack-test
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '2.1'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '2.1'
111
+ description: Ruby gem for Rails APM integration with MiniAPM. Exports traces in OTLP
112
+ format, captures errors, and provides comprehensive instrumentation for Rails, ActiveRecord,
113
+ Sidekiq, HTTP clients, Redis, and search engines.
114
+ email:
115
+ - krzysztof.hasinski@gmail.com
116
+ executables: []
117
+ extensions: []
118
+ extra_rdoc_files: []
119
+ files:
120
+ - CHANGELOG.md
121
+ - LICENSE
122
+ - README.md
123
+ - lib/generators/miniapm/install_generator.rb
124
+ - lib/generators/miniapm/templates/README
125
+ - lib/generators/miniapm/templates/initializer.rb
126
+ - lib/miniapm.rb
127
+ - lib/miniapm/configuration.rb
128
+ - lib/miniapm/context.rb
129
+ - lib/miniapm/error_event.rb
130
+ - lib/miniapm/exporters/errors.rb
131
+ - lib/miniapm/exporters/otlp.rb
132
+ - lib/miniapm/instrumentations/activejob.rb
133
+ - lib/miniapm/instrumentations/activerecord.rb
134
+ - lib/miniapm/instrumentations/base.rb
135
+ - lib/miniapm/instrumentations/cache.rb
136
+ - lib/miniapm/instrumentations/http/faraday.rb
137
+ - lib/miniapm/instrumentations/http/httparty.rb
138
+ - lib/miniapm/instrumentations/http/net_http.rb
139
+ - lib/miniapm/instrumentations/rails/controller.rb
140
+ - lib/miniapm/instrumentations/rails/railtie.rb
141
+ - lib/miniapm/instrumentations/redis/redis.rb
142
+ - lib/miniapm/instrumentations/redis/redis_client.rb
143
+ - lib/miniapm/instrumentations/registry.rb
144
+ - lib/miniapm/instrumentations/search/elasticsearch.rb
145
+ - lib/miniapm/instrumentations/search/opensearch.rb
146
+ - lib/miniapm/instrumentations/search/searchkick.rb
147
+ - lib/miniapm/instrumentations/sidekiq.rb
148
+ - lib/miniapm/middleware/error_handler.rb
149
+ - lib/miniapm/middleware/rack.rb
150
+ - lib/miniapm/span.rb
151
+ - lib/miniapm/testing.rb
152
+ - lib/miniapm/trace.rb
153
+ - lib/miniapm/transport/batch_sender.rb
154
+ - lib/miniapm/transport/http.rb
155
+ - lib/miniapm/version.rb
156
+ homepage: https://miniapm.com
157
+ licenses:
158
+ - MIT
159
+ metadata:
160
+ homepage_uri: https://miniapm.com
161
+ source_code_uri: https://github.com/miniapm/miniapm-ruby
162
+ changelog_uri: https://github.com/miniapm/miniapm-ruby/blob/main/CHANGELOG.md
163
+ documentation_uri: https://miniapm.com/docs
164
+ post_install_message:
165
+ rdoc_options: []
166
+ require_paths:
167
+ - lib
168
+ required_ruby_version: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - ">="
171
+ - !ruby/object:Gem::Version
172
+ version: 3.0.0
173
+ required_rubygems_version: !ruby/object:Gem::Requirement
174
+ requirements:
175
+ - - ">="
176
+ - !ruby/object:Gem::Version
177
+ version: '0'
178
+ requirements: []
179
+ rubygems_version: 3.5.22
180
+ signing_key:
181
+ specification_version: 4
182
+ summary: Lightweight APM client for MiniAPM server
183
+ test_files: []