logtide 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.
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/http"
4
+ require "uri"
5
+ require "json"
6
+ require "time"
7
+ require "timeout"
8
+ require_relative "http"
9
+
10
+ module Logtide
11
+ module Transport
12
+ # Exports spans as OTLP/JSON to /v1/otlp/traces (spec 005 section 3).
13
+ # Shares the retryable/network-error contract with the log transport.
14
+ class Otlp
15
+ USER_AGENT = "logtide-ruby/#{Logtide::VERSION}".freeze
16
+
17
+ def initialize(url:, api_key:, resource:, timeout: 10)
18
+ @uri = URI.parse(url)
19
+ @api_key = api_key
20
+ @resource = resource
21
+ @timeout = timeout
22
+ end
23
+
24
+ def deliver(spans)
25
+ body = JSON.generate(payload(spans))
26
+ response = client.request(build_request(body))
27
+ Response.new(status: response.code.to_i, retry_after: nil)
28
+ rescue *HTTP::NETWORK_ERRORS => e
29
+ raise NetworkError, e.message
30
+ end
31
+
32
+ private
33
+
34
+ def payload(spans)
35
+ {
36
+ "resourceSpans" => [
37
+ {
38
+ "resource" => { "attributes" => resource_attributes },
39
+ "scopeSpans" => [{ "spans" => spans.map(&:to_otlp) }]
40
+ }
41
+ ]
42
+ }
43
+ end
44
+
45
+ def resource_attributes
46
+ [
47
+ string_attribute("service.name", @resource[:service_name]),
48
+ string_attribute("deployment.environment", @resource[:environment]),
49
+ string_attribute("service.version", @resource[:service_version])
50
+ ].compact
51
+ end
52
+
53
+ def string_attribute(key, value)
54
+ return nil if value.nil?
55
+
56
+ { "key" => key, "value" => { "stringValue" => value.to_s } }
57
+ end
58
+
59
+ def client
60
+ http = Net::HTTP.new(@uri.host, @uri.port)
61
+ http.use_ssl = @uri.scheme == "https"
62
+ http.open_timeout = @timeout
63
+ http.read_timeout = @timeout
64
+ http.write_timeout = @timeout if http.respond_to?(:write_timeout=)
65
+ http
66
+ end
67
+
68
+ def build_request(body)
69
+ request = Net::HTTP::Post.new(@uri.request_uri)
70
+ request["X-API-Key"] = @api_key
71
+ request["Content-Type"] = "application/json"
72
+ request["User-Agent"] = USER_AGENT
73
+ request.body = body
74
+ request
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Logtide
4
+ VERSION = "1.0.0"
5
+
6
+ # The spec version this SDK implements (see logtide-sdk-spec).
7
+ SPEC_VERSION = "1.0"
8
+ end
data/lib/logtide.rb ADDED
@@ -0,0 +1,152 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "logtide/version"
4
+ require_relative "logtide/error"
5
+ require_relative "logtide/dsn"
6
+ require_relative "logtide/configuration"
7
+ require_relative "logtide/circuit_breaker"
8
+ require_relative "logtide/retry_policy"
9
+ require_relative "logtide/metrics"
10
+ require_relative "logtide/transport/buffer"
11
+ require_relative "logtide/transport/http"
12
+ require_relative "logtide/transport/batcher"
13
+ require_relative "logtide/structured_exception"
14
+ require_relative "logtide/breadcrumb"
15
+ require_relative "logtide/tracing"
16
+ require_relative "logtide/tracing/span"
17
+ require_relative "logtide/transport/otlp"
18
+ require_relative "logtide/scope"
19
+ require_relative "logtide/event"
20
+ require_relative "logtide/client"
21
+ require_relative "logtide/hub"
22
+ require_relative "logtide/logger_bridge"
23
+ require_relative "logtide/rack/middleware"
24
+ require_relative "logtide/rails/railtie" if defined?(Rails::Railtie)
25
+
26
+ # LogTide SDK for Ruby. The module-level methods are the documented entry point
27
+ # (spec 004 section 1); they delegate to the current Hub.
28
+ module Logtide
29
+ class << self
30
+ # Initialise the SDK and bind the global Hub. Returns the Hub.
31
+ def init(**options)
32
+ hub = Hub.new(Client.new(Configuration.new(**options)))
33
+ @main_hub = hub
34
+ register_shutdown
35
+ hub
36
+ end
37
+
38
+ def main_hub
39
+ @main_hub ||= Hub.new(nil)
40
+ end
41
+
42
+ def current_hub
43
+ Thread.current[:logtide_hub] || main_hub
44
+ end
45
+
46
+ def current_hub=(hub)
47
+ Thread.current[:logtide_hub] = hub
48
+ end
49
+
50
+ # Run a block with a per-request hub cloned from the main hub, then restore
51
+ # the previous hub. Used by framework middleware for request isolation.
52
+ def with_request_hub
53
+ previous = Thread.current[:logtide_hub]
54
+ self.current_hub = main_hub.clone
55
+ yield current_hub
56
+ ensure
57
+ Thread.current[:logtide_hub] = previous
58
+ end
59
+
60
+ def capture_log(level, message, metadata = nil, **opts)
61
+ current_hub.capture_log(level, message, metadata, **opts)
62
+ end
63
+
64
+ def debug(message, metadata = nil, **opts)
65
+ capture_log("debug", message, metadata, **opts)
66
+ end
67
+
68
+ def info(message, metadata = nil, **opts)
69
+ capture_log("info", message, metadata, **opts)
70
+ end
71
+
72
+ def warn(message, metadata = nil, **opts)
73
+ capture_log("warn", message, metadata, **opts)
74
+ end
75
+
76
+ def error(message, metadata_or_exception = nil, **opts)
77
+ if metadata_or_exception.is_a?(Exception)
78
+ return capture_exception(metadata_or_exception, message: message, level: "error", **opts)
79
+ end
80
+
81
+ capture_log("error", message, metadata_or_exception, **opts)
82
+ end
83
+
84
+ def critical(message, metadata_or_exception = nil, **opts)
85
+ if metadata_or_exception.is_a?(Exception)
86
+ return capture_exception(metadata_or_exception, message: message, level: "critical", **opts)
87
+ end
88
+
89
+ capture_log("critical", message, metadata_or_exception, **opts)
90
+ end
91
+
92
+ def capture_exception(exception, **opts)
93
+ current_hub.capture_exception(exception, **opts)
94
+ end
95
+ alias capture_error capture_exception
96
+
97
+ def configure_scope(&)
98
+ current_hub.configure_scope(&)
99
+ end
100
+
101
+ def with_scope(&)
102
+ current_hub.with_scope(&)
103
+ end
104
+
105
+ def add_breadcrumb(breadcrumb)
106
+ current_hub.add_breadcrumb(breadcrumb)
107
+ end
108
+
109
+ def start_span(name, ...)
110
+ current_hub.start_span(name, ...)
111
+ end
112
+
113
+ def trace_propagation_headers
114
+ current_hub.trace_propagation_headers
115
+ end
116
+
117
+ def set_user(user)
118
+ configure_scope { |scope| scope.set_user(user) }
119
+ end
120
+
121
+ def set_tag(key, value)
122
+ configure_scope { |scope| scope.set_tag(key, value) }
123
+ end
124
+
125
+ def flush(timeout = nil)
126
+ current_hub.flush(timeout)
127
+ end
128
+
129
+ def close(timeout = nil)
130
+ current_hub.close(timeout)
131
+ end
132
+
133
+ def get_metrics
134
+ current_hub.client&.metrics
135
+ end
136
+
137
+ # Test/teardown seam: drop the bound hubs.
138
+ def reset!
139
+ Thread.current[:logtide_hub] = nil
140
+ @main_hub = nil
141
+ end
142
+
143
+ private
144
+
145
+ def register_shutdown
146
+ return if @shutdown_registered
147
+
148
+ @shutdown_registered = true
149
+ at_exit { @main_hub&.close }
150
+ end
151
+ end
152
+ end
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: logtide
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - LogTide
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-06-17 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Log management, tracing and error tracking for Ruby and Rails. Captures
14
+ logs, exceptions and spans and ships them to a LogTide instance.
15
+ email:
16
+ - hello@logtide.dev
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - CHANGELOG.md
22
+ - LICENSE
23
+ - README.md
24
+ - lib/logtide.rb
25
+ - lib/logtide/breadcrumb.rb
26
+ - lib/logtide/circuit_breaker.rb
27
+ - lib/logtide/client.rb
28
+ - lib/logtide/configuration.rb
29
+ - lib/logtide/dsn.rb
30
+ - lib/logtide/error.rb
31
+ - lib/logtide/event.rb
32
+ - lib/logtide/hub.rb
33
+ - lib/logtide/logger_bridge.rb
34
+ - lib/logtide/metrics.rb
35
+ - lib/logtide/rack/middleware.rb
36
+ - lib/logtide/rails/railtie.rb
37
+ - lib/logtide/retry_policy.rb
38
+ - lib/logtide/scope.rb
39
+ - lib/logtide/structured_exception.rb
40
+ - lib/logtide/tracing.rb
41
+ - lib/logtide/tracing/span.rb
42
+ - lib/logtide/transport/batcher.rb
43
+ - lib/logtide/transport/buffer.rb
44
+ - lib/logtide/transport/http.rb
45
+ - lib/logtide/transport/otlp.rb
46
+ - lib/logtide/version.rb
47
+ homepage: https://github.com/logtide-dev/logtide-ruby
48
+ licenses:
49
+ - MIT
50
+ metadata:
51
+ homepage_uri: https://github.com/logtide-dev/logtide-ruby
52
+ source_code_uri: https://github.com/logtide-dev/logtide-ruby
53
+ changelog_uri: https://github.com/logtide-dev/logtide-ruby/blob/main/CHANGELOG.md
54
+ post_install_message:
55
+ rdoc_options: []
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: 3.1.0
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ requirements: []
69
+ rubygems_version: 3.5.22
70
+ signing_key:
71
+ specification_version: 4
72
+ summary: Official LogTide SDK for Ruby
73
+ test_files: []