alertiqo 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: aacacaa175b56e656658758e85b0a95b53660b608f4091aafca16a720bc28d1c
4
+ data.tar.gz: 2a4ab278096013f53d5ba3ef68b86ed1489be1b53be7fd935d753323f4df7272
5
+ SHA512:
6
+ metadata.gz: 6fa1f2e38cf13d483b2f9f3507a4cc579b4d1f82a01993fcbe23a3f68828f5e45cecef7e1318077f395b155dea0c5af2dc7a5ab8d1145f4cd8beb0f551528c10
7
+ data.tar.gz: e73982c00557def886362d26c4654ac633140ccfe84afd50fb276399b8604c5f3fdd21af74a42b53eb99cc309618eb3d35ecfdeaf21313e6a00726e04074c94d
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Muhammad Hamizi Jaminan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,141 @@
1
+ # Alertiqo Ruby SDK
2
+
3
+ Error tracking SDK for Ruby and Rails applications.
4
+
5
+ ## Installation
6
+
7
+ Add to your Gemfile:
8
+
9
+ ```ruby
10
+ gem 'alertiqo'
11
+ ```
12
+
13
+ Then run:
14
+
15
+ ```bash
16
+ bundle install
17
+ ```
18
+
19
+ Or install directly:
20
+
21
+ ```bash
22
+ gem install alertiqo
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ ### Basic Setup
28
+
29
+ ```ruby
30
+ require 'alertiqo'
31
+
32
+ Alertiqo.configure do |config|
33
+ config.api_key = 'your-api-key'
34
+ config.endpoint = 'https://alertiqo.hamizi.net'
35
+ config.environment = 'production'
36
+ config.release = '1.0.0'
37
+ end
38
+
39
+ Alertiqo.init
40
+ ```
41
+
42
+ ### Rails Setup
43
+
44
+ Create an initializer `config/initializers/alertiqo.rb`:
45
+
46
+ ```ruby
47
+ Alertiqo.configure do |config|
48
+ config.api_key = ENV['ALERTIQO_API_KEY']
49
+ config.endpoint = ENV['ALERTIQO_ENDPOINT'] || 'https://alertiqo.hamizi.net'
50
+ config.environment = Rails.env
51
+ config.release = ENV['APP_VERSION']
52
+ end
53
+ ```
54
+
55
+ Add to your `application.rb`:
56
+
57
+ ```ruby
58
+ require 'alertiqo/rails'
59
+ ```
60
+
61
+ ### Capture Exceptions
62
+
63
+ ```ruby
64
+ begin
65
+ some_risky_operation
66
+ rescue => e
67
+ Alertiqo.capture_exception(e)
68
+ end
69
+ ```
70
+
71
+ ### Capture Messages
72
+
73
+ ```ruby
74
+ Alertiqo.capture_message("User completed checkout", level: "info")
75
+ ```
76
+
77
+ ### Add Breadcrumbs
78
+
79
+ ```ruby
80
+ Alertiqo.add_breadcrumb(
81
+ "User clicked button",
82
+ category: "user-action",
83
+ level: "info",
84
+ data: { button_id: "submit-btn" }
85
+ )
86
+ ```
87
+
88
+ ### Set User Context
89
+
90
+ ```ruby
91
+ Alertiqo.set_user(
92
+ id: "12345",
93
+ email: "user@example.com",
94
+ username: "johndoe"
95
+ )
96
+ ```
97
+
98
+ ### Set Tags
99
+
100
+ ```ruby
101
+ Alertiqo.set_tag("page", "checkout")
102
+ Alertiqo.set_tags({
103
+ feature: "payments",
104
+ version: "2.1.0"
105
+ })
106
+ ```
107
+
108
+ ## Configuration Options
109
+
110
+ ```ruby
111
+ Alertiqo.configure do |config|
112
+ # Required
113
+ config.api_key = 'your-api-key'
114
+ config.endpoint = 'https://alertiqo.hamizi.net'
115
+
116
+ # Optional
117
+ config.environment = 'production' # Default: RACK_ENV or RAILS_ENV
118
+ config.release = '1.0.0' # App version
119
+ config.tags = { app: 'myapp' } # Default tags
120
+ config.enabled = true # Enable/disable tracking
121
+ config.capture_unhandled = true # Auto-capture unhandled exceptions
122
+
123
+ # Filter/modify errors before sending
124
+ config.before_send = ->(report) {
125
+ # Return nil to skip sending
126
+ # Return modified report to send
127
+ report
128
+ }
129
+ end
130
+ ```
131
+
132
+ ## Environment Variables
133
+
134
+ ```bash
135
+ ALERTIQO_API_KEY=your-api-key
136
+ ALERTIQO_ENDPOINT=https://alertiqo.hamizi.net
137
+ ```
138
+
139
+ ## License
140
+
141
+ MIT
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alertiqo
4
+ class Breadcrumb
5
+ attr_reader :timestamp, :message, :category, :level, :data
6
+
7
+ def initialize(message:, category: "default", level: "info", data: {})
8
+ @timestamp = (Time.now.to_f * 1000).to_i
9
+ @message = message
10
+ @category = category
11
+ @level = level
12
+ @data = data
13
+ end
14
+
15
+ def to_h
16
+ {
17
+ timestamp: @timestamp,
18
+ message: @message,
19
+ category: @category,
20
+ level: @level,
21
+ data: @data
22
+ }
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,163 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "faraday"
4
+ require "json"
5
+ require "socket"
6
+
7
+ module Alertiqo
8
+ class Client
9
+ MAX_BREADCRUMBS = 100
10
+
11
+ def initialize(configuration)
12
+ @config = configuration
13
+ @breadcrumbs = []
14
+ @user = {}
15
+ @tags = {}
16
+ @initialized = false
17
+ @mutex = Mutex.new
18
+ end
19
+
20
+ def init
21
+ return if @initialized
22
+
23
+ @initialized = true
24
+
25
+ if @config.capture_unhandled
26
+ setup_exception_handler
27
+ end
28
+ end
29
+
30
+ def capture_exception(exception, **options)
31
+ return unless @config.enabled
32
+
33
+ report = build_error_report(
34
+ message: exception.message,
35
+ stack: exception.backtrace&.join("\n"),
36
+ level: options[:level] || "error",
37
+ tags: options[:tags] || {}
38
+ )
39
+
40
+ send_report(report)
41
+ end
42
+
43
+ def capture_message(message, level: "info", **options)
44
+ return unless @config.enabled
45
+
46
+ report = build_error_report(
47
+ message: message,
48
+ stack: nil,
49
+ level: level,
50
+ tags: options[:tags] || {}
51
+ )
52
+
53
+ send_report(report)
54
+ end
55
+
56
+ def add_breadcrumb(message, category: "default", level: "info", data: {})
57
+ @mutex.synchronize do
58
+ breadcrumb = Breadcrumb.new(
59
+ message: message,
60
+ category: category,
61
+ level: level,
62
+ data: data
63
+ )
64
+
65
+ @breadcrumbs << breadcrumb
66
+ @breadcrumbs.shift if @breadcrumbs.size > MAX_BREADCRUMBS
67
+ end
68
+ end
69
+
70
+ def set_user(id: nil, email: nil, username: nil)
71
+ @mutex.synchronize do
72
+ @user = { id: id, email: email, username: username }.compact
73
+ end
74
+ end
75
+
76
+ def set_tag(key, value)
77
+ @mutex.synchronize do
78
+ @tags[key.to_s] = value
79
+ end
80
+ end
81
+
82
+ def set_tags(tags)
83
+ @mutex.synchronize do
84
+ tags.each { |k, v| @tags[k.to_s] = v }
85
+ end
86
+ end
87
+
88
+ private
89
+
90
+ def setup_exception_handler
91
+ at_exit do
92
+ if $! && !$!.is_a?(SystemExit)
93
+ capture_exception($!)
94
+ end
95
+ end
96
+ end
97
+
98
+ def build_error_report(message:, stack:, level:, tags:)
99
+ merged_tags = @config.tags.merge(@tags).merge(tags)
100
+
101
+ @mutex.synchronize do
102
+ if @user[:id]
103
+ merged_tags["userId"] = @user[:id]
104
+ end
105
+ if @user[:email]
106
+ merged_tags["userEmail"] = @user[:email]
107
+ end
108
+ end
109
+
110
+ {
111
+ message: message,
112
+ stack: stack,
113
+ level: level,
114
+ timestamp: (Time.now.to_f * 1000).to_i,
115
+ environment: @config.environment,
116
+ release: @config.release,
117
+ tags: merged_tags,
118
+ context: get_context,
119
+ breadcrumbs: get_breadcrumbs
120
+ }
121
+ end
122
+
123
+ def get_context
124
+ {
125
+ runtime: "ruby",
126
+ rubyVersion: RUBY_VERSION,
127
+ platform: RUBY_PLATFORM,
128
+ hostname: Socket.gethostname
129
+ }
130
+ end
131
+
132
+ def get_breadcrumbs
133
+ @mutex.synchronize do
134
+ @breadcrumbs.map(&:to_h)
135
+ end
136
+ end
137
+
138
+ def send_report(report)
139
+ if @config.before_send
140
+ report = @config.before_send.call(report)
141
+ return if report.nil?
142
+ end
143
+
144
+ Thread.new do
145
+ begin
146
+ conn = Faraday.new(url: @config.endpoint) do |f|
147
+ f.request :json
148
+ f.response :json
149
+ f.adapter Faraday.default_adapter
150
+ end
151
+
152
+ conn.post("/api/errors") do |req|
153
+ req.headers["Content-Type"] = "application/json"
154
+ req.headers["X-API-Key"] = @config.api_key
155
+ req.body = report.to_json
156
+ end
157
+ rescue StandardError => e
158
+ warn "[Alertiqo] Failed to send error report: #{e.message}"
159
+ end
160
+ end
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alertiqo
4
+ class Configuration
5
+ attr_accessor :api_key, :endpoint, :environment, :release, :tags,
6
+ :before_send, :capture_unhandled, :enabled
7
+
8
+ def initialize
9
+ @api_key = ENV["ALERTIQO_API_KEY"]
10
+ @endpoint = ENV["ALERTIQO_ENDPOINT"] || "https://alertiqo.hamizi.net"
11
+ @environment = ENV["RACK_ENV"] || ENV["RAILS_ENV"] || "production"
12
+ @release = nil
13
+ @tags = {}
14
+ @before_send = nil
15
+ @capture_unhandled = true
16
+ @enabled = true
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "alertiqo"
4
+
5
+ module Alertiqo
6
+ class Railtie < Rails::Railtie
7
+ initializer "alertiqo.configure_rails_initialization" do |app|
8
+ app.config.middleware.use Alertiqo::RackMiddleware
9
+ end
10
+
11
+ config.after_initialize do
12
+ Alertiqo.init if Alertiqo.configuration&.capture_unhandled
13
+ end
14
+ end
15
+
16
+ class RackMiddleware
17
+ def initialize(app)
18
+ @app = app
19
+ end
20
+
21
+ def call(env)
22
+ begin
23
+ Alertiqo.add_breadcrumb(
24
+ "#{env['REQUEST_METHOD']} #{env['PATH_INFO']}",
25
+ category: "http",
26
+ level: "info",
27
+ data: {
28
+ method: env["REQUEST_METHOD"],
29
+ path: env["PATH_INFO"],
30
+ query: env["QUERY_STRING"]
31
+ }
32
+ )
33
+
34
+ @app.call(env)
35
+ rescue Exception => e
36
+ Alertiqo.capture_exception(e, tags: {
37
+ route: env["PATH_INFO"],
38
+ method: env["REQUEST_METHOD"]
39
+ })
40
+ raise
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alertiqo
4
+ VERSION = "1.0.0"
5
+ end
data/lib/alertiqo.rb ADDED
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "alertiqo/version"
4
+ require_relative "alertiqo/client"
5
+ require_relative "alertiqo/configuration"
6
+ require_relative "alertiqo/breadcrumb"
7
+
8
+ module Alertiqo
9
+ class Error < StandardError; end
10
+
11
+ class << self
12
+ attr_accessor :configuration
13
+
14
+ def configure
15
+ self.configuration ||= Configuration.new
16
+ yield(configuration) if block_given?
17
+ end
18
+
19
+ def client
20
+ @client ||= Client.new(configuration)
21
+ end
22
+
23
+ def init
24
+ client.init
25
+ end
26
+
27
+ def capture_exception(exception, **options)
28
+ client.capture_exception(exception, **options)
29
+ end
30
+
31
+ def capture_message(message, level: "info", **options)
32
+ client.capture_message(message, level: level, **options)
33
+ end
34
+
35
+ def add_breadcrumb(message, category: "default", level: "info", data: {})
36
+ client.add_breadcrumb(message, category: category, level: level, data: data)
37
+ end
38
+
39
+ def set_user(id: nil, email: nil, username: nil)
40
+ client.set_user(id: id, email: email, username: username)
41
+ end
42
+
43
+ def set_tag(key, value)
44
+ client.set_tag(key, value)
45
+ end
46
+
47
+ def set_tags(tags)
48
+ client.set_tags(tags)
49
+ end
50
+ end
51
+ end
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: alertiqo
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Muhammad Hamizi Jaminan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2025-12-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
27
+ description: Error tracking SDK for Ruby and Rails applications
28
+ email:
29
+ - hello@hamizi.net
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - Gemfile
35
+ - LICENSE
36
+ - README.md
37
+ - lib/alertiqo.rb
38
+ - lib/alertiqo/breadcrumb.rb
39
+ - lib/alertiqo/client.rb
40
+ - lib/alertiqo/configuration.rb
41
+ - lib/alertiqo/rails.rb
42
+ - lib/alertiqo/version.rb
43
+ homepage: https://github.com/hymns/alertiqo-client-ruby
44
+ licenses:
45
+ - MIT
46
+ metadata:
47
+ homepage_uri: https://github.com/hymns/alertiqo-client-ruby
48
+ source_code_uri: https://github.com/hymns/alertiqo-client-ruby
49
+ changelog_uri: https://github.com/hymns/alertiqo-client-ruby/blob/master/CHANGELOG.md
50
+ post_install_message:
51
+ rdoc_options: []
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: 2.7.0
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ requirements: []
65
+ rubygems_version: 3.0.3.1
66
+ signing_key:
67
+ specification_version: 4
68
+ summary: Alertiqo SDK for Ruby error tracking
69
+ test_files: []