fluyenta-ruby 0.1.14
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 +7 -0
- data/CHANGELOG.md +68 -0
- data/LICENSE +11 -0
- data/README.md +571 -0
- data/lib/brainzlab/beacon/client.rb +227 -0
- data/lib/brainzlab/beacon/provisioner.rb +44 -0
- data/lib/brainzlab/beacon.rb +215 -0
- data/lib/brainzlab/configuration.rb +676 -0
- data/lib/brainzlab/context.rb +90 -0
- data/lib/brainzlab/cortex/cache.rb +59 -0
- data/lib/brainzlab/cortex/client.rb +159 -0
- data/lib/brainzlab/cortex/provisioner.rb +49 -0
- data/lib/brainzlab/cortex.rb +223 -0
- data/lib/brainzlab/debug.rb +305 -0
- data/lib/brainzlab/dendrite/client.rb +250 -0
- data/lib/brainzlab/dendrite/provisioner.rb +44 -0
- data/lib/brainzlab/dendrite.rb +195 -0
- data/lib/brainzlab/development/logger.rb +150 -0
- data/lib/brainzlab/development/store.rb +121 -0
- data/lib/brainzlab/development.rb +72 -0
- data/lib/brainzlab/devtools/assets/devtools.css +1329 -0
- data/lib/brainzlab/devtools/assets/devtools.js +396 -0
- data/lib/brainzlab/devtools/assets/logo.svg +6 -0
- data/lib/brainzlab/devtools/assets/templates/debug_panel.html.erb +511 -0
- data/lib/brainzlab/devtools/assets/templates/error_page.html.erb +1086 -0
- data/lib/brainzlab/devtools/data/collector.rb +248 -0
- data/lib/brainzlab/devtools/middleware/asset_server.rb +63 -0
- data/lib/brainzlab/devtools/middleware/database_handler.rb +177 -0
- data/lib/brainzlab/devtools/middleware/debug_panel.rb +126 -0
- data/lib/brainzlab/devtools/middleware/error_page.rb +377 -0
- data/lib/brainzlab/devtools/renderers/debug_panel_renderer.rb +159 -0
- data/lib/brainzlab/devtools/renderers/error_page_renderer.rb +98 -0
- data/lib/brainzlab/devtools.rb +75 -0
- data/lib/brainzlab/errors.rb +490 -0
- data/lib/brainzlab/flux/buffer.rb +96 -0
- data/lib/brainzlab/flux/client.rb +68 -0
- data/lib/brainzlab/flux/provisioner.rb +124 -0
- data/lib/brainzlab/flux.rb +184 -0
- data/lib/brainzlab/instrumentation/action_cable.rb +351 -0
- data/lib/brainzlab/instrumentation/action_controller.rb +649 -0
- data/lib/brainzlab/instrumentation/action_dispatch.rb +259 -0
- data/lib/brainzlab/instrumentation/action_mailbox.rb +197 -0
- data/lib/brainzlab/instrumentation/action_mailer.rb +182 -0
- data/lib/brainzlab/instrumentation/action_view.rb +380 -0
- data/lib/brainzlab/instrumentation/active_job.rb +569 -0
- data/lib/brainzlab/instrumentation/active_record.rb +559 -0
- data/lib/brainzlab/instrumentation/active_storage.rb +541 -0
- data/lib/brainzlab/instrumentation/active_support_cache.rb +730 -0
- data/lib/brainzlab/instrumentation/aws.rb +183 -0
- data/lib/brainzlab/instrumentation/dalli.rb +108 -0
- data/lib/brainzlab/instrumentation/delayed_job.rb +234 -0
- data/lib/brainzlab/instrumentation/elasticsearch.rb +209 -0
- data/lib/brainzlab/instrumentation/excon.rb +152 -0
- data/lib/brainzlab/instrumentation/faraday.rb +181 -0
- data/lib/brainzlab/instrumentation/good_job.rb +102 -0
- data/lib/brainzlab/instrumentation/grape.rb +293 -0
- data/lib/brainzlab/instrumentation/graphql.rb +252 -0
- data/lib/brainzlab/instrumentation/httparty.rb +193 -0
- data/lib/brainzlab/instrumentation/mongodb.rb +187 -0
- data/lib/brainzlab/instrumentation/net_http.rb +114 -0
- data/lib/brainzlab/instrumentation/rails_deprecation.rb +139 -0
- data/lib/brainzlab/instrumentation/railties.rb +134 -0
- data/lib/brainzlab/instrumentation/redis.rb +324 -0
- data/lib/brainzlab/instrumentation/resque.rb +114 -0
- data/lib/brainzlab/instrumentation/sidekiq.rb +265 -0
- data/lib/brainzlab/instrumentation/solid_queue.rb +194 -0
- data/lib/brainzlab/instrumentation/stripe.rb +163 -0
- data/lib/brainzlab/instrumentation/typhoeus.rb +106 -0
- data/lib/brainzlab/instrumentation.rb +360 -0
- data/lib/brainzlab/nerve/client.rb +235 -0
- data/lib/brainzlab/nerve/provisioner.rb +44 -0
- data/lib/brainzlab/nerve.rb +219 -0
- data/lib/brainzlab/pulse/client.rb +203 -0
- data/lib/brainzlab/pulse/instrumentation.rb +401 -0
- data/lib/brainzlab/pulse/propagation.rb +241 -0
- data/lib/brainzlab/pulse/provisioner.rb +114 -0
- data/lib/brainzlab/pulse/tracer.rb +111 -0
- data/lib/brainzlab/pulse.rb +294 -0
- data/lib/brainzlab/rails/log_formatter.rb +807 -0
- data/lib/brainzlab/rails/log_subscriber.rb +334 -0
- data/lib/brainzlab/rails/railtie.rb +606 -0
- data/lib/brainzlab/recall/buffer.rb +66 -0
- data/lib/brainzlab/recall/client.rb +158 -0
- data/lib/brainzlab/recall/logger.rb +116 -0
- data/lib/brainzlab/recall/provisioner.rb +130 -0
- data/lib/brainzlab/recall.rb +175 -0
- data/lib/brainzlab/reflex/breadcrumbs.rb +55 -0
- data/lib/brainzlab/reflex/client.rb +150 -0
- data/lib/brainzlab/reflex/provisioner.rb +116 -0
- data/lib/brainzlab/reflex.rb +421 -0
- data/lib/brainzlab/sentinel/client.rb +236 -0
- data/lib/brainzlab/sentinel/provisioner.rb +44 -0
- data/lib/brainzlab/sentinel.rb +165 -0
- data/lib/brainzlab/signal/client.rb +60 -0
- data/lib/brainzlab/signal/provisioner.rb +115 -0
- data/lib/brainzlab/signal.rb +136 -0
- data/lib/brainzlab/synapse/client.rb +308 -0
- data/lib/brainzlab/synapse/provisioner.rb +44 -0
- data/lib/brainzlab/synapse.rb +270 -0
- data/lib/brainzlab/testing/event_store.rb +377 -0
- data/lib/brainzlab/testing/helpers.rb +650 -0
- data/lib/brainzlab/testing/matchers.rb +391 -0
- data/lib/brainzlab/testing.rb +327 -0
- data/lib/brainzlab/utilities/circuit_breaker.rb +290 -0
- data/lib/brainzlab/utilities/health_check.rb +294 -0
- data/lib/brainzlab/utilities/log_formatter.rb +254 -0
- data/lib/brainzlab/utilities/rate_limiter.rb +230 -0
- data/lib/brainzlab/utilities.rb +17 -0
- data/lib/brainzlab/vault/cache.rb +80 -0
- data/lib/brainzlab/vault/client.rb +216 -0
- data/lib/brainzlab/vault/provisioner.rb +49 -0
- data/lib/brainzlab/vault.rb +262 -0
- data/lib/brainzlab/version.rb +5 -0
- data/lib/brainzlab/vision/client.rb +175 -0
- data/lib/brainzlab/vision/provisioner.rb +136 -0
- data/lib/brainzlab/vision.rb +155 -0
- data/lib/brainzlab-sdk.rb +3 -0
- data/lib/brainzlab.rb +306 -0
- data/lib/generators/brainzlab/install/install_generator.rb +63 -0
- data/lib/generators/brainzlab/install/templates/brainzlab.rb.tt +77 -0
- metadata +251 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'vision/client'
|
|
4
|
+
require_relative 'vision/provisioner'
|
|
5
|
+
|
|
6
|
+
module BrainzLab
|
|
7
|
+
module Vision
|
|
8
|
+
class << self
|
|
9
|
+
# Execute an autonomous AI task
|
|
10
|
+
# @param instruction [String] Natural language instruction for the AI
|
|
11
|
+
# @param start_url [String] URL to start from
|
|
12
|
+
# @param model [String] LLM model to use (default: claude-sonnet-4)
|
|
13
|
+
# @param browser_provider [String] Browser provider (default: local)
|
|
14
|
+
# @param max_steps [Integer] Maximum steps to execute (default: 50)
|
|
15
|
+
# @param timeout [Integer] Timeout in seconds (default: 300)
|
|
16
|
+
# @return [Hash] Task result with extracted data
|
|
17
|
+
def execute_task(instruction:, start_url:, model: nil, browser_provider: nil, max_steps: 50, timeout: 300)
|
|
18
|
+
config = BrainzLab.configuration
|
|
19
|
+
return { error: 'Vision is not enabled' } unless config.vision_enabled
|
|
20
|
+
|
|
21
|
+
ensure_provisioned!
|
|
22
|
+
return { error: 'Vision credentials not configured' } unless config.vision_valid?
|
|
23
|
+
|
|
24
|
+
client.execute_task(
|
|
25
|
+
instruction: instruction,
|
|
26
|
+
start_url: start_url,
|
|
27
|
+
model: model,
|
|
28
|
+
browser_provider: browser_provider,
|
|
29
|
+
max_steps: max_steps,
|
|
30
|
+
timeout: timeout
|
|
31
|
+
)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Create a browser session
|
|
35
|
+
# @param url [String] Optional initial URL
|
|
36
|
+
# @param viewport [Hash] Viewport dimensions { width:, height: }
|
|
37
|
+
# @param browser_provider [String] Browser provider to use
|
|
38
|
+
# @return [Hash] Session info with session_id
|
|
39
|
+
def create_session(url: nil, viewport: nil, browser_provider: nil)
|
|
40
|
+
config = BrainzLab.configuration
|
|
41
|
+
return { error: 'Vision is not enabled' } unless config.vision_enabled
|
|
42
|
+
|
|
43
|
+
ensure_provisioned!
|
|
44
|
+
return { error: 'Vision credentials not configured' } unless config.vision_valid?
|
|
45
|
+
|
|
46
|
+
client.create_session(
|
|
47
|
+
url: url,
|
|
48
|
+
viewport: viewport,
|
|
49
|
+
browser_provider: browser_provider
|
|
50
|
+
)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Perform an AI-powered action in a session
|
|
54
|
+
# @param session_id [String] Session ID
|
|
55
|
+
# @param instruction [String] Natural language instruction
|
|
56
|
+
# @param model [String] LLM model to use
|
|
57
|
+
# @return [Hash] Action result
|
|
58
|
+
def ai_action(session_id:, instruction:, model: nil)
|
|
59
|
+
config = BrainzLab.configuration
|
|
60
|
+
return { error: 'Vision is not enabled' } unless config.vision_enabled
|
|
61
|
+
return { error: 'Vision credentials not configured' } unless config.vision_valid?
|
|
62
|
+
|
|
63
|
+
client.ai_action(
|
|
64
|
+
session_id: session_id,
|
|
65
|
+
instruction: instruction,
|
|
66
|
+
model: model
|
|
67
|
+
)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Perform a direct browser action
|
|
71
|
+
# @param session_id [String] Session ID
|
|
72
|
+
# @param action [Symbol] Action type (:click, :type, :scroll, etc.)
|
|
73
|
+
# @param selector [String] Element selector
|
|
74
|
+
# @param value [String] Value for type/fill actions
|
|
75
|
+
# @return [Hash] Action result
|
|
76
|
+
def perform(session_id:, action:, selector: nil, value: nil)
|
|
77
|
+
config = BrainzLab.configuration
|
|
78
|
+
return { error: 'Vision is not enabled' } unless config.vision_enabled
|
|
79
|
+
return { error: 'Vision credentials not configured' } unless config.vision_valid?
|
|
80
|
+
|
|
81
|
+
client.perform(
|
|
82
|
+
session_id: session_id,
|
|
83
|
+
action: action,
|
|
84
|
+
selector: selector,
|
|
85
|
+
value: value
|
|
86
|
+
)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Extract structured data from the page
|
|
90
|
+
# @param session_id [String] Session ID
|
|
91
|
+
# @param schema [Hash] JSON schema for extraction
|
|
92
|
+
# @param instruction [String] Optional instruction for extraction
|
|
93
|
+
# @return [Hash] Extracted data
|
|
94
|
+
def extract(session_id:, schema:, instruction: nil)
|
|
95
|
+
config = BrainzLab.configuration
|
|
96
|
+
return { error: 'Vision is not enabled' } unless config.vision_enabled
|
|
97
|
+
return { error: 'Vision credentials not configured' } unless config.vision_valid?
|
|
98
|
+
|
|
99
|
+
client.extract(
|
|
100
|
+
session_id: session_id,
|
|
101
|
+
schema: schema,
|
|
102
|
+
instruction: instruction
|
|
103
|
+
)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Close a browser session
|
|
107
|
+
# @param session_id [String] Session ID
|
|
108
|
+
# @return [Hash] Close result
|
|
109
|
+
def close_session(session_id:)
|
|
110
|
+
config = BrainzLab.configuration
|
|
111
|
+
return { error: 'Vision is not enabled' } unless config.vision_enabled
|
|
112
|
+
return { error: 'Vision credentials not configured' } unless config.vision_valid?
|
|
113
|
+
|
|
114
|
+
client.close_session(session_id: session_id)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Take a screenshot
|
|
118
|
+
# @param session_id [String] Session ID
|
|
119
|
+
# @param full_page [Boolean] Capture full page (default: true)
|
|
120
|
+
# @return [Hash] Screenshot data
|
|
121
|
+
def screenshot(session_id:, full_page: true)
|
|
122
|
+
config = BrainzLab.configuration
|
|
123
|
+
return { error: 'Vision is not enabled' } unless config.vision_enabled
|
|
124
|
+
return { error: 'Vision credentials not configured' } unless config.vision_valid?
|
|
125
|
+
|
|
126
|
+
client.screenshot(session_id: session_id, full_page: full_page)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Ensure project is auto-provisioned
|
|
130
|
+
def ensure_provisioned!
|
|
131
|
+
config = BrainzLab.configuration
|
|
132
|
+
puts "[BrainzLab::Debug] Vision.ensure_provisioned! called, @provisioned=#{@provisioned}" if config.debug
|
|
133
|
+
|
|
134
|
+
return if @provisioned
|
|
135
|
+
|
|
136
|
+
@provisioned = true
|
|
137
|
+
provisioner.ensure_project!
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def provisioner
|
|
141
|
+
@provisioner ||= Provisioner.new(BrainzLab.configuration)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def client
|
|
145
|
+
@client ||= Client.new(BrainzLab.configuration)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def reset!
|
|
149
|
+
@client = nil
|
|
150
|
+
@provisioner = nil
|
|
151
|
+
@provisioned = false
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
data/lib/brainzlab.rb
ADDED
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# BrainzLab SDK - Official Ruby SDK for BrainzLab products
|
|
4
|
+
#
|
|
5
|
+
# For testing utilities, require 'brainzlab/testing' in your test helper:
|
|
6
|
+
#
|
|
7
|
+
# require 'brainzlab/testing'
|
|
8
|
+
#
|
|
9
|
+
# RSpec.configure do |config|
|
|
10
|
+
# config.include BrainzLab::Testing::Helpers
|
|
11
|
+
# end
|
|
12
|
+
#
|
|
13
|
+
# See BrainzLab::Testing for more details.
|
|
14
|
+
|
|
15
|
+
require_relative 'brainzlab/version'
|
|
16
|
+
require_relative 'brainzlab/errors'
|
|
17
|
+
require_relative 'brainzlab/configuration'
|
|
18
|
+
require_relative 'brainzlab/debug'
|
|
19
|
+
require_relative 'brainzlab/context'
|
|
20
|
+
require_relative 'brainzlab/recall'
|
|
21
|
+
require_relative 'brainzlab/reflex'
|
|
22
|
+
require_relative 'brainzlab/pulse'
|
|
23
|
+
require_relative 'brainzlab/flux'
|
|
24
|
+
require_relative 'brainzlab/signal'
|
|
25
|
+
require_relative 'brainzlab/vault'
|
|
26
|
+
require_relative 'brainzlab/vision'
|
|
27
|
+
require_relative 'brainzlab/cortex'
|
|
28
|
+
require_relative 'brainzlab/beacon'
|
|
29
|
+
require_relative 'brainzlab/nerve'
|
|
30
|
+
require_relative 'brainzlab/dendrite'
|
|
31
|
+
require_relative 'brainzlab/sentinel'
|
|
32
|
+
require_relative 'brainzlab/synapse'
|
|
33
|
+
require_relative 'brainzlab/instrumentation'
|
|
34
|
+
require_relative 'brainzlab/utilities'
|
|
35
|
+
require_relative 'brainzlab/development'
|
|
36
|
+
|
|
37
|
+
module BrainzLab
|
|
38
|
+
# Thread-local re-entrancy guard for instrumentation.
|
|
39
|
+
# When true, SDK operations that would make HTTP calls are skipped
|
|
40
|
+
# to prevent recursive instrumentation from blocking the host app.
|
|
41
|
+
INSTRUMENTING_KEY = :brainzlab_instrumenting
|
|
42
|
+
|
|
43
|
+
class << self
|
|
44
|
+
# Returns true when inside an instrumentation handler.
|
|
45
|
+
# Used by Recall.log, Pulse.record_metric, etc. to skip HTTP calls
|
|
46
|
+
# that would block the host app during notification callbacks.
|
|
47
|
+
def instrumenting?
|
|
48
|
+
Thread.current[INSTRUMENTING_KEY] == true
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Executes a block within the instrumentation guard.
|
|
52
|
+
# Prevents recursive/cascading SDK HTTP calls from instrumentation handlers.
|
|
53
|
+
def with_instrumentation_guard
|
|
54
|
+
return if Thread.current[INSTRUMENTING_KEY]
|
|
55
|
+
|
|
56
|
+
Thread.current[INSTRUMENTING_KEY] = true
|
|
57
|
+
begin
|
|
58
|
+
yield
|
|
59
|
+
ensure
|
|
60
|
+
Thread.current[INSTRUMENTING_KEY] = nil
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def configure
|
|
65
|
+
yield(configuration) if block_given?
|
|
66
|
+
configuration
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def configuration
|
|
70
|
+
@configuration ||= Configuration.new
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def reset_configuration!
|
|
74
|
+
@configuration = Configuration.new
|
|
75
|
+
Recall.reset!
|
|
76
|
+
Reflex.reset!
|
|
77
|
+
Pulse.reset!
|
|
78
|
+
Flux.reset!
|
|
79
|
+
Signal.reset!
|
|
80
|
+
Vault.reset!
|
|
81
|
+
Vision.reset!
|
|
82
|
+
Cortex.reset!
|
|
83
|
+
Beacon.reset!
|
|
84
|
+
Nerve.reset!
|
|
85
|
+
Dendrite.reset!
|
|
86
|
+
Sentinel.reset!
|
|
87
|
+
Synapse.reset!
|
|
88
|
+
Development.reset!
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Context management
|
|
92
|
+
def set_user(id: nil, email: nil, name: nil, **extra)
|
|
93
|
+
Context.current.set_user(id: id, email: email, name: name, **extra)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def set_context(**data)
|
|
97
|
+
Context.current.set_context(**data)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def set_tags(**data)
|
|
101
|
+
Context.current.set_tags(**data)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def with_context(**data, &)
|
|
105
|
+
Context.current.with_context(**data, &)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def clear_context!
|
|
109
|
+
Context.clear!
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Breadcrumb helpers
|
|
113
|
+
def add_breadcrumb(message, category: 'default', level: :info, data: nil)
|
|
114
|
+
Reflex.add_breadcrumb(message, category: category, level: level, data: data)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def clear_breadcrumbs!
|
|
118
|
+
Reflex.clear_breadcrumbs!
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Create a logger that can replace Rails.logger
|
|
122
|
+
# @param broadcast_to [Logger] Optional logger to also send logs to (e.g., original Rails.logger)
|
|
123
|
+
# @return [BrainzLab::Recall::Logger]
|
|
124
|
+
def logger(broadcast_to: nil)
|
|
125
|
+
Recall::Logger.new(nil, broadcast_to: broadcast_to)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Debug logging helper
|
|
129
|
+
def debug_log(message)
|
|
130
|
+
configuration.debug_log(message)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Check if debug mode is enabled
|
|
134
|
+
def debug?
|
|
135
|
+
configuration.debug?
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Query events stored in development mode
|
|
139
|
+
# @param service [Symbol, nil] filter by service (:recall, :reflex, :pulse, etc.)
|
|
140
|
+
# @param event_type [String, nil] filter by event type ('log', 'error', 'trace', etc.)
|
|
141
|
+
# @param since [Time, nil] filter events after this time
|
|
142
|
+
# @param limit [Integer] max number of events to return (default: 100)
|
|
143
|
+
# @return [Array<Hash>] matching events
|
|
144
|
+
# @example
|
|
145
|
+
# BrainzLab.development_events # All events
|
|
146
|
+
# BrainzLab.development_events(service: :recall) # Only Recall logs
|
|
147
|
+
# BrainzLab.development_events(service: :reflex, limit: 10) # Last 10 errors
|
|
148
|
+
# BrainzLab.development_events(since: 1.hour.ago) # Events from last hour
|
|
149
|
+
def development_events(service: nil, event_type: nil, since: nil, limit: 100)
|
|
150
|
+
Development.events(service: service, event_type: event_type, since: since, limit: limit)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Clear all events stored in development mode
|
|
154
|
+
def clear_development_events!
|
|
155
|
+
Development.clear!
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# Get stats about stored development events
|
|
159
|
+
# @return [Hash] counts by service
|
|
160
|
+
def development_stats
|
|
161
|
+
Development.stats
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Health check - verifies connectivity to all enabled services
|
|
165
|
+
# @return [Hash] Status of each service
|
|
166
|
+
def health_check
|
|
167
|
+
results = { status: 'ok', services: {} }
|
|
168
|
+
|
|
169
|
+
# Check Recall
|
|
170
|
+
if configuration.recall_enabled
|
|
171
|
+
results[:services][:recall] = check_service_health(
|
|
172
|
+
url: configuration.recall_url,
|
|
173
|
+
name: 'Recall'
|
|
174
|
+
)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Check Reflex
|
|
178
|
+
if configuration.reflex_enabled
|
|
179
|
+
results[:services][:reflex] = check_service_health(
|
|
180
|
+
url: configuration.reflex_url,
|
|
181
|
+
name: 'Reflex'
|
|
182
|
+
)
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# Check Pulse
|
|
186
|
+
if configuration.pulse_enabled
|
|
187
|
+
results[:services][:pulse] = check_service_health(
|
|
188
|
+
url: configuration.pulse_url,
|
|
189
|
+
name: 'Pulse'
|
|
190
|
+
)
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# Check Flux
|
|
194
|
+
if configuration.flux_enabled
|
|
195
|
+
results[:services][:flux] = check_service_health(
|
|
196
|
+
url: configuration.flux_url,
|
|
197
|
+
name: 'Flux'
|
|
198
|
+
)
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
# Check Signal
|
|
202
|
+
if configuration.signal_enabled
|
|
203
|
+
results[:services][:signal] = check_service_health(
|
|
204
|
+
url: configuration.signal_url,
|
|
205
|
+
name: 'Signal'
|
|
206
|
+
)
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# Check Vault
|
|
210
|
+
if configuration.vault_enabled
|
|
211
|
+
results[:services][:vault] = check_service_health(
|
|
212
|
+
url: configuration.vault_url,
|
|
213
|
+
name: 'Vault'
|
|
214
|
+
)
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# Check Vision
|
|
218
|
+
if configuration.vision_enabled
|
|
219
|
+
results[:services][:vision] = check_service_health(
|
|
220
|
+
url: configuration.vision_url,
|
|
221
|
+
name: 'Vision'
|
|
222
|
+
)
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# Check Cortex
|
|
226
|
+
if configuration.cortex_enabled
|
|
227
|
+
results[:services][:cortex] = check_service_health(
|
|
228
|
+
url: configuration.cortex_url,
|
|
229
|
+
name: 'Cortex'
|
|
230
|
+
)
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
# Check Beacon
|
|
234
|
+
if configuration.beacon_enabled
|
|
235
|
+
results[:services][:beacon] = check_service_health(
|
|
236
|
+
url: configuration.beacon_url,
|
|
237
|
+
name: 'Beacon'
|
|
238
|
+
)
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# Check Nerve
|
|
242
|
+
if configuration.nerve_enabled
|
|
243
|
+
results[:services][:nerve] = check_service_health(
|
|
244
|
+
url: configuration.nerve_url,
|
|
245
|
+
name: 'Nerve'
|
|
246
|
+
)
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
# Check Dendrite
|
|
250
|
+
if configuration.dendrite_enabled
|
|
251
|
+
results[:services][:dendrite] = check_service_health(
|
|
252
|
+
url: configuration.dendrite_url,
|
|
253
|
+
name: 'Dendrite'
|
|
254
|
+
)
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# Check Sentinel
|
|
258
|
+
if configuration.sentinel_enabled
|
|
259
|
+
results[:services][:sentinel] = check_service_health(
|
|
260
|
+
url: configuration.sentinel_url,
|
|
261
|
+
name: 'Sentinel'
|
|
262
|
+
)
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
# Check Synapse
|
|
266
|
+
if configuration.synapse_enabled
|
|
267
|
+
results[:services][:synapse] = check_service_health(
|
|
268
|
+
url: configuration.synapse_url,
|
|
269
|
+
name: 'Synapse'
|
|
270
|
+
)
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
# Overall status
|
|
274
|
+
has_failure = results[:services].values.any? { |s| s[:status] == 'error' }
|
|
275
|
+
results[:status] = has_failure ? 'degraded' : 'ok'
|
|
276
|
+
|
|
277
|
+
results
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
private
|
|
281
|
+
|
|
282
|
+
def check_service_health(url:, name:)
|
|
283
|
+
require 'net/http'
|
|
284
|
+
require 'uri'
|
|
285
|
+
|
|
286
|
+
uri = URI.parse("#{url}/up")
|
|
287
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
288
|
+
http.use_ssl = uri.scheme == 'https'
|
|
289
|
+
http.open_timeout = 5
|
|
290
|
+
http.read_timeout = 5
|
|
291
|
+
|
|
292
|
+
response = http.get(uri.request_uri)
|
|
293
|
+
|
|
294
|
+
if response.is_a?(Net::HTTPSuccess)
|
|
295
|
+
{ status: 'ok', latency_ms: 0 }
|
|
296
|
+
else
|
|
297
|
+
{ status: 'error', message: "HTTP #{response.code}" }
|
|
298
|
+
end
|
|
299
|
+
rescue StandardError => e
|
|
300
|
+
{ status: 'error', message: e.message }
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
# Auto-load Rails integration if Rails is available
|
|
306
|
+
require_relative 'brainzlab/rails/railtie' if defined?(Rails::Railtie)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rails/generators/base'
|
|
4
|
+
|
|
5
|
+
module Brainzlab
|
|
6
|
+
module Generators
|
|
7
|
+
class InstallGenerator < Rails::Generators::Base
|
|
8
|
+
source_root File.expand_path('templates', __dir__)
|
|
9
|
+
|
|
10
|
+
desc 'Creates a BrainzLab initializer for your Rails application'
|
|
11
|
+
|
|
12
|
+
class_option :key, type: :string, desc: 'Your BrainzLab secret key'
|
|
13
|
+
class_option :replace_logger, type: :boolean, default: false, desc: 'Replace Rails.logger with BrainzLab logger'
|
|
14
|
+
|
|
15
|
+
def copy_initializer
|
|
16
|
+
template 'brainzlab.rb.tt', 'config/initializers/brainzlab.rb'
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def show_post_install_message
|
|
20
|
+
say ''
|
|
21
|
+
say 'BrainzLab SDK installed successfully!', :green
|
|
22
|
+
say ''
|
|
23
|
+
say 'Next steps:'
|
|
24
|
+
say ' 1. Set your environment variables:'
|
|
25
|
+
say ' BRAINZLAB_SECRET_KEY - Your API key from https://brainzlab.ai/dashboard'
|
|
26
|
+
say ''
|
|
27
|
+
say ' Or for auto-provisioning:'
|
|
28
|
+
say ' RECALL_MASTER_KEY - Master key for Recall auto-provisioning'
|
|
29
|
+
say ' REFLEX_MASTER_KEY - Master key for Reflex auto-provisioning'
|
|
30
|
+
say ''
|
|
31
|
+
say ' 2. Start logging:'
|
|
32
|
+
say " BrainzLab::Recall.info('Hello from BrainzLab!')"
|
|
33
|
+
say ''
|
|
34
|
+
say ' 3. Capture errors (automatic with Rails, or manual):'
|
|
35
|
+
say ' BrainzLab::Reflex.capture(exception)'
|
|
36
|
+
say ''
|
|
37
|
+
if options[:replace_logger]
|
|
38
|
+
say ' Rails.logger is now connected to Recall!', :yellow
|
|
39
|
+
else
|
|
40
|
+
say ' To send all Rails logs to Recall, add to your initializer:'
|
|
41
|
+
say ' Rails.logger = BrainzLab.logger(broadcast_to: Rails.logger)'
|
|
42
|
+
end
|
|
43
|
+
say ''
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
def secret_key_value
|
|
49
|
+
if options[:key].present?
|
|
50
|
+
%("#{options[:key]}")
|
|
51
|
+
else
|
|
52
|
+
'ENV["BRAINZLAB_SECRET_KEY"]'
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def app_name
|
|
57
|
+
Rails.application.class.module_parent_name.underscore
|
|
58
|
+
rescue StandardError
|
|
59
|
+
'my-app'
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
BrainzLab.configure do |config|
|
|
4
|
+
# Your secret key from https://brainzlab.ai/dashboard
|
|
5
|
+
# If using auto-provisioning, you can omit this and set master keys instead
|
|
6
|
+
config.secret_key = <%= secret_key_value %>
|
|
7
|
+
|
|
8
|
+
# App name for auto-provisioning (required for auto-provision)
|
|
9
|
+
config.app_name = "<%= app_name %>"
|
|
10
|
+
|
|
11
|
+
# Environment (defaults to Rails.env)
|
|
12
|
+
# config.environment = Rails.env
|
|
13
|
+
|
|
14
|
+
# Service name (defaults to app name)
|
|
15
|
+
config.service = "<%= app_name %>"
|
|
16
|
+
|
|
17
|
+
# ============================================================================
|
|
18
|
+
# Recall - Logging
|
|
19
|
+
# ============================================================================
|
|
20
|
+
|
|
21
|
+
# Enable/disable Recall logging
|
|
22
|
+
# config.recall_enabled = true
|
|
23
|
+
|
|
24
|
+
# Recall URL (defaults to https://recall.brainzlab.ai)
|
|
25
|
+
# config.recall_url = ENV.fetch("RECALL_URL", "https://recall.brainzlab.ai")
|
|
26
|
+
|
|
27
|
+
# Master key for auto-provisioning (set in environment)
|
|
28
|
+
# config.recall_master_key = ENV["RECALL_MASTER_KEY"]
|
|
29
|
+
|
|
30
|
+
# Minimum log level to send to Recall
|
|
31
|
+
# config.recall_min_level = :debug # :debug, :info, :warn, :error, :fatal
|
|
32
|
+
|
|
33
|
+
# Buffer settings for batching logs
|
|
34
|
+
# config.recall_buffer_size = 50 # Flush after 50 logs
|
|
35
|
+
# config.recall_flush_interval = 5 # Or every 5 seconds
|
|
36
|
+
|
|
37
|
+
# ============================================================================
|
|
38
|
+
# Reflex - Error Tracking
|
|
39
|
+
# ============================================================================
|
|
40
|
+
|
|
41
|
+
# Enable/disable Reflex error tracking
|
|
42
|
+
# config.reflex_enabled = true
|
|
43
|
+
|
|
44
|
+
# Reflex URL (defaults to https://reflex.brainzlab.ai)
|
|
45
|
+
# config.reflex_url = ENV.fetch("REFLEX_URL", "https://reflex.brainzlab.ai")
|
|
46
|
+
|
|
47
|
+
# Master key for auto-provisioning (set in environment)
|
|
48
|
+
# config.reflex_master_key = ENV["REFLEX_MASTER_KEY"]
|
|
49
|
+
|
|
50
|
+
# Exceptions to exclude from Reflex error tracking
|
|
51
|
+
# config.reflex_excluded_exceptions = [
|
|
52
|
+
# "ActionController::RoutingError",
|
|
53
|
+
# "ActionController::InvalidAuthenticityToken",
|
|
54
|
+
# "ActiveRecord::RecordNotFound"
|
|
55
|
+
# ]
|
|
56
|
+
|
|
57
|
+
# Sample rate for errors (1.0 = 100%, 0.5 = 50%)
|
|
58
|
+
# config.reflex_sample_rate = 1.0
|
|
59
|
+
|
|
60
|
+
# Before send hook to modify or filter errors
|
|
61
|
+
# config.reflex_before_send = ->(payload, exception) {
|
|
62
|
+
# # Return nil to drop the error, or modify and return payload
|
|
63
|
+
# payload
|
|
64
|
+
# }
|
|
65
|
+
|
|
66
|
+
# ============================================================================
|
|
67
|
+
# General
|
|
68
|
+
# ============================================================================
|
|
69
|
+
|
|
70
|
+
# Fields to scrub from logs and errors
|
|
71
|
+
# config.scrub_fields = %i[password password_confirmation token api_key secret credit_card]
|
|
72
|
+
end
|
|
73
|
+
<% if options[:replace_logger] %>
|
|
74
|
+
|
|
75
|
+
# Send all Rails logs to Recall (keeps console output too)
|
|
76
|
+
Rails.logger = BrainzLab.logger(broadcast_to: Rails.logger)
|
|
77
|
+
<% end %>
|