boringmetrics 0.1.0 → 0.1.1
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.
- checksums.yaml +4 -4
- data/README.md +5 -5
- data/lib/boringmetrics/client.rb +21 -9
- data/lib/boringmetrics/configuration.rb +8 -6
- data/lib/boringmetrics/live_methods.rb +2 -2
- data/lib/boringmetrics/log_methods.rb +2 -2
- data/lib/boringmetrics/transport.rb +35 -5
- data/lib/boringmetrics/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3a6ff99943f8ac4392d0e93cc3f51218a3c5da561edea2bed7a9451a8bb57f9a
|
4
|
+
data.tar.gz: 4b47319ce4fed4e44c2eaf8086a710caf3007272701bd8e5e8d736418a84108f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cd0595624e8c1fc3bb91f9ab84e165127465584b332da529c48029d70b1c5573829c30c15fac1bc206b10986035f38a201a6c5a1778995854709289c752cfc19
|
7
|
+
data.tar.gz: f9da4c53864c3b790152e8ede052a5ce2ec5c73392c6640e4b3d6f39f507c5759dd72301b7825c240969a666ba784388255ee2941f377b8f44305fb828bd084c
|
data/README.md
CHANGED
@@ -47,7 +47,7 @@ BoringMetrics.logs.send(
|
|
47
47
|
type: "log",
|
48
48
|
level: "info",
|
49
49
|
message: "User signed in",
|
50
|
-
data: {
|
50
|
+
data: { userId: "123" },
|
51
51
|
)
|
52
52
|
|
53
53
|
# Send multiple logs
|
@@ -58,14 +58,14 @@ BoringMetrics.logs.send_batch([
|
|
58
58
|
|
59
59
|
# Set a live metric value
|
60
60
|
BoringMetrics.lives.update(
|
61
|
-
|
61
|
+
liveId: "metric-123",
|
62
62
|
value: 42,
|
63
63
|
operation: "set",
|
64
64
|
)
|
65
65
|
|
66
66
|
# Increment a live metric value
|
67
67
|
BoringMetrics.lives.update(
|
68
|
-
|
68
|
+
liveId: "metric-123",
|
69
69
|
value: 5,
|
70
70
|
operation: "increment",
|
71
71
|
)
|
@@ -78,8 +78,8 @@ In a Rails application, you can initialize the SDK in an initializer:
|
|
78
78
|
```ruby
|
79
79
|
# config/initializers/boringmetrics.rb
|
80
80
|
BoringMetrics::Rails.initialize("YOUR_API_TOKEN", {
|
81
|
-
|
82
|
-
|
81
|
+
logsMaxBatchSize: 50,
|
82
|
+
logsSendInterval: 10
|
83
83
|
})
|
84
84
|
```
|
85
85
|
|
data/lib/boringmetrics/client.rb
CHANGED
@@ -15,7 +15,7 @@ module BoringMetrics
|
|
15
15
|
def initialize(token, **config)
|
16
16
|
@config = Configuration.new(token, **config)
|
17
17
|
@transport = Transport.new(@config)
|
18
|
-
|
18
|
+
|
19
19
|
@logs_queue = Concurrent::Array.new
|
20
20
|
@logs_mutex = Mutex.new
|
21
21
|
@logs_timer = nil
|
@@ -34,12 +34,18 @@ module BoringMetrics
|
|
34
34
|
# @return [void]
|
35
35
|
def add_log(log)
|
36
36
|
log_with_sent_at = log.dup
|
37
|
-
|
37
|
+
|
38
|
+
# Support both snake_case and camelCase
|
39
|
+
if log_with_sent_at[:sentAt].nil? && log_with_sent_at[:sent_at].nil?
|
40
|
+
log_with_sent_at[:sentAt] = Time.now.iso8601
|
41
|
+
elsif log_with_sent_at[:sent_at] && log_with_sent_at[:sentAt].nil?
|
42
|
+
log_with_sent_at[:sentAt] = log_with_sent_at[:sent_at]
|
43
|
+
end
|
38
44
|
|
39
45
|
@logs_mutex.synchronize do
|
40
46
|
@logs_queue << log_with_sent_at
|
41
|
-
|
42
|
-
if @logs_queue.size >= @config.
|
47
|
+
|
48
|
+
if @logs_queue.size >= @config.logsMaxBatchSize
|
43
49
|
flush_logs
|
44
50
|
elsif @logs_timer.nil?
|
45
51
|
schedule_logs_flush
|
@@ -53,12 +59,18 @@ module BoringMetrics
|
|
53
59
|
# @return [void]
|
54
60
|
def update_live(update)
|
55
61
|
update_with_sent_at = update.dup
|
56
|
-
|
62
|
+
|
63
|
+
# Support both snake_case and camelCase
|
64
|
+
if update_with_sent_at[:sentAt].nil? && update_with_sent_at[:sent_at].nil?
|
65
|
+
update_with_sent_at[:sentAt] = Time.now.iso8601
|
66
|
+
elsif update_with_sent_at[:sent_at] && update_with_sent_at[:sentAt].nil?
|
67
|
+
update_with_sent_at[:sentAt] = update_with_sent_at[:sent_at]
|
68
|
+
end
|
57
69
|
|
58
70
|
@lives_mutex.synchronize do
|
59
71
|
@lives_queue << update_with_sent_at
|
60
|
-
|
61
|
-
if @lives_queue.size >= @config.
|
72
|
+
|
73
|
+
if @lives_queue.size >= @config.livesMaxBatchSize
|
62
74
|
flush_lives
|
63
75
|
elsif @lives_timer.nil?
|
64
76
|
schedule_lives_flush
|
@@ -69,7 +81,7 @@ module BoringMetrics
|
|
69
81
|
private
|
70
82
|
|
71
83
|
def schedule_logs_flush
|
72
|
-
@logs_timer = Concurrent::ScheduledTask.execute(@config.
|
84
|
+
@logs_timer = Concurrent::ScheduledTask.execute(@config.logsSendInterval) do
|
73
85
|
flush_logs
|
74
86
|
end
|
75
87
|
end
|
@@ -99,7 +111,7 @@ module BoringMetrics
|
|
99
111
|
end
|
100
112
|
|
101
113
|
def schedule_lives_flush
|
102
|
-
@lives_timer = Concurrent::ScheduledTask.execute(@config.
|
114
|
+
@lives_timer = Concurrent::ScheduledTask.execute(@config.livesDebounceTime) do
|
103
115
|
flush_lives
|
104
116
|
end
|
105
117
|
end
|
@@ -2,13 +2,15 @@
|
|
2
2
|
|
3
3
|
module BoringMetrics
|
4
4
|
class Configuration
|
5
|
-
attr_accessor :
|
6
|
-
|
5
|
+
attr_accessor :apiUrl, :maxRetryAttempts, :logsMaxBatchSize, :logsSendInterval, :livesMaxBatchSize, :livesDebounceTime
|
6
|
+
|
7
7
|
def initialize
|
8
|
-
@
|
9
|
-
@
|
10
|
-
@
|
11
|
-
@
|
8
|
+
@apiUrl = "https://api.getboringmetrics.com"
|
9
|
+
@maxRetryAttempts = 5
|
10
|
+
@logsMaxBatchSize = 100
|
11
|
+
@logsSendInterval = 5 # seconds
|
12
|
+
@livesMaxBatchSize = 20
|
13
|
+
@livesDebounceTime = 1 # seconds
|
12
14
|
end
|
13
15
|
end
|
14
16
|
end
|
@@ -13,10 +13,10 @@ module BoringMetrics
|
|
13
13
|
# Update a live metric value
|
14
14
|
#
|
15
15
|
# @param update [Hash] The live update to send
|
16
|
-
# @option update [String] :
|
16
|
+
# @option update [String] :liveId The ID of the live metric
|
17
17
|
# @option update [Numeric] :value The value to set or increment
|
18
18
|
# @option update [String] :operation The operation to perform ("set" or "increment")
|
19
|
-
# @option update [String] :
|
19
|
+
# @option update [String] :sentAt ISO8601 date - will be automatically set if not provided
|
20
20
|
# @return [void]
|
21
21
|
def update(update)
|
22
22
|
@client.update_live(update)
|
@@ -17,8 +17,8 @@ module BoringMetrics
|
|
17
17
|
# @option log [String] :level The log level (trace, debug, info, warn, error, fatal)
|
18
18
|
# @option log [String] :message The log message
|
19
19
|
# @option log [Hash] :data Additional structured data (optional)
|
20
|
-
# @option log [String] :
|
21
|
-
# @option log [String] :
|
20
|
+
# @option log [String] :sessionId Session identifier for grouping related logs (optional)
|
21
|
+
# @option log [String] :sentAt ISO8601 date - will be automatically set if not provided
|
22
22
|
# @return [void]
|
23
23
|
def send(log)
|
24
24
|
@client.add_log(log)
|
@@ -18,11 +18,27 @@ module BoringMetrics
|
|
18
18
|
# @param logs [Array<Hash>] The logs to send
|
19
19
|
# @return [void]
|
20
20
|
def send_logs(logs)
|
21
|
+
# Convert from Ruby style to camelCase for API
|
22
|
+
api_logs = logs.map do |log|
|
23
|
+
api_log = {}
|
24
|
+
log.each do |key, value|
|
25
|
+
case key.to_s
|
26
|
+
when "sent_at"
|
27
|
+
api_log[:sentAt] = value
|
28
|
+
when "session_id"
|
29
|
+
api_log[:sessionId] = value
|
30
|
+
else
|
31
|
+
api_log[key] = value
|
32
|
+
end
|
33
|
+
end
|
34
|
+
api_log
|
35
|
+
end
|
36
|
+
|
21
37
|
with_retry do
|
22
38
|
response = connection.post("/api/v1/logs") do |req|
|
23
39
|
req.headers["Content-Type"] = "application/json"
|
24
40
|
req.headers["Authorization"] = "Bearer #{@config.token}"
|
25
|
-
req.body = { logs:
|
41
|
+
req.body = { logs: api_logs }.to_json
|
26
42
|
end
|
27
43
|
|
28
44
|
raise "Failed to send logs: #{response.status}" unless response.success?
|
@@ -34,11 +50,25 @@ module BoringMetrics
|
|
34
50
|
# @param update [Hash] The live update to send
|
35
51
|
# @return [void]
|
36
52
|
def update_live(update)
|
53
|
+
# Convert from Ruby style to camelCase for API
|
54
|
+
api_update = {}
|
55
|
+
update.each do |key, value|
|
56
|
+
case key.to_s
|
57
|
+
when "live_id"
|
58
|
+
api_update[:liveId] = value
|
59
|
+
when "sent_at"
|
60
|
+
api_update[:sentAt] = value
|
61
|
+
else
|
62
|
+
api_update[key] = value
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
37
66
|
with_retry do
|
38
|
-
|
67
|
+
live_id = update[:live_id] || update[:liveId]
|
68
|
+
response = connection.put("/api/v1/lives/#{live_id}") do |req|
|
39
69
|
req.headers["Content-Type"] = "application/json"
|
40
70
|
req.headers["Authorization"] = "Bearer #{@config.token}"
|
41
|
-
req.body = { live:
|
71
|
+
req.body = { live: api_update }.to_json
|
42
72
|
end
|
43
73
|
|
44
74
|
raise "Failed to send live update: #{response.status}" unless response.success?
|
@@ -48,7 +78,7 @@ module BoringMetrics
|
|
48
78
|
private
|
49
79
|
|
50
80
|
def connection
|
51
|
-
@connection ||= Faraday.new(url:
|
81
|
+
@connection ||= Faraday.new(url: @config.apiUrl) do |faraday|
|
52
82
|
faraday.adapter Faraday.default_adapter
|
53
83
|
end
|
54
84
|
end
|
@@ -59,7 +89,7 @@ module BoringMetrics
|
|
59
89
|
yield
|
60
90
|
rescue StandardError => e
|
61
91
|
retries += 1
|
62
|
-
if retries <= @config.
|
92
|
+
if retries <= @config.maxRetryAttempts
|
63
93
|
sleep(2**retries * 0.1) # Exponential backoff
|
64
94
|
retry
|
65
95
|
else
|