-
Notifications
You must be signed in to change notification settings - Fork 67
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(CE): sentry destinator connector
- Loading branch information
Raushan Kumar Raman
committed
Dec 13, 2024
1 parent
05bb9fa
commit 8dd0440
Showing
11 changed files
with
334 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
110 changes: 110 additions & 0 deletions
110
integrations/lib/multiwoven/integrations/destination/sentry/client.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
# frozen_string_literal: true | ||
|
||
require "sentry-ruby" | ||
|
||
module Multiwoven::Integrations::Destination | ||
module Sentry | ||
include Multiwoven::Integrations::Core | ||
class Client < DestinationConnector | ||
attr_reader :dsn_link | ||
|
||
def initialize(connection_config) | ||
@dsn_link = connection_config[:dsn] | ||
configure_sentry(connection_config) | ||
end | ||
|
||
def check_connection | ||
response = Multiwoven::Integrations::Core::HttpClient.request( | ||
host, | ||
"POST", | ||
headers: { | ||
"Content-Type" => "application/json", | ||
"X-Sentry-Auth" => "Sentry sentry_version=7, sentry_key=#{public_key}" | ||
} | ||
) | ||
if response[:code].to_i == 200 | ||
success_status | ||
else | ||
failure_status | ||
end | ||
rescue StandardError => e | ||
handle_exception(e, | ||
context: "SENTRY::CONNECTION::FAILURE", | ||
type: "error") | ||
failure_status | ||
end | ||
|
||
def write(sync_config, records) | ||
@sync_config = sync_config | ||
process_records(records) | ||
rescue StandardError => e | ||
handle_exception(e, { | ||
context: "SENTRY:WRITE:EXCEPTION", | ||
type: "error", | ||
sync_id: @sync_config.sync_id, | ||
sync_run_id: @sync_config.sync_run_id | ||
}) | ||
end | ||
|
||
private | ||
|
||
def process_records(sync_config, records) | ||
write_success = 0 | ||
write_failure = 0 | ||
records.each do |record| | ||
::Sentry.capture_exception(record) | ||
write_success += 1 | ||
rescue StandardError => e | ||
write_failure += 1 | ||
handle_exception(e, { | ||
context: "SENTRY:WRITE:EXCEPTION", | ||
type: "error", | ||
sync_id: sync_config.sync_id, | ||
sync_run_id: sync_config.sync_run_id | ||
}) | ||
end | ||
end | ||
|
||
def configure_sentry(connection_config) | ||
::Sentry.init do |config| | ||
config.dsn = connection_config[:dsn] | ||
config.environment = connection_config[:environment] | ||
config.release = connection_config[:release] || "default-release" | ||
config.debug = connection_config[:debug] || true | ||
config.traces_sample_rate = connection_config[:traces_sample_rate] || 0.5 | ||
config.breadcrumbs_logger = %i[active_support_logger http_logger] | ||
config.background_worker_threads = connection_config[:worker_threads] || 5 | ||
|
||
config.excluded_exceptions = connection_config[:excluded_exceptions] || [] | ||
config.before_send = lambda do |_even, hint| | ||
if hint[:exception] && config.excluded_exceptions.any? { |e| hint[:exception].is_a?(e) } | ||
nil | ||
else | ||
event | ||
end | ||
end | ||
end | ||
end | ||
|
||
def dsn | ||
@dsn ||= ::Sentry::DSN.new(@dsn_link) | ||
end | ||
|
||
def host | ||
@host ||= dsn.host | ||
end | ||
|
||
def public_key | ||
@public_key ||= dsn.public_key | ||
end | ||
|
||
def success_status | ||
ConnectionStatus.new(status: ConnectionStatusType["succeeded"]).to_multiwoven_message | ||
end | ||
|
||
def failure_status(_exception = nil) | ||
ConnectionStatus.new(status: ConnectionStatusType["failed"]).to_multiwoven_message | ||
end | ||
end | ||
end | ||
end |
16 changes: 16 additions & 0 deletions
16
integrations/lib/multiwoven/integrations/destination/sentry/config/meta.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{ | ||
"data": { | ||
"name": "Sentry", | ||
"title": "Sentry", | ||
"connector_type": "destination", | ||
"category": "Productivity Tools", | ||
"documentation_url": "https://docs.squared.ai/guides/data-integration/destination/sentry", | ||
"github_issue_label": "destination-sentry", | ||
"icon": "icon.svg", | ||
"license": "MIT", | ||
"release_stage": "alpha", | ||
"support_level": "community", | ||
"tags": ["language:ruby", "multiwoven"] | ||
} | ||
} | ||
|
60 changes: 60 additions & 0 deletions
60
integrations/lib/multiwoven/integrations/destination/sentry/config/spec.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
{ | ||
"documentationUrl": "https://docs.squared.ai/guides/data-integration/destination/sentry", | ||
"changelogUrl": "https://docs.squared.ai/guides/data-integration/destination/sentry#changelog", | ||
"streamType": "dynamic", | ||
"connectionSpecification": { | ||
"type": "object", | ||
"required": "[dsn environment]", | ||
"properties": { | ||
"dsn": { | ||
"type": "string", | ||
"description": "The Data Source Name (DSN) for your Sentry project. This is used to identify and authenticate with your Sentry instance." | ||
}, | ||
"environment": { | ||
"type": "string", | ||
"description": "The environment name (e.g., production, staging, or development) to associate with the events sent to Sentry.", | ||
"examples": "[production staging development]" | ||
}, | ||
"release": { | ||
"type": "string", | ||
"description": "The version of the application associated with the events. This can help in tracking issues across deployments.", | ||
"default": "default-release", | ||
"examples": ["1.0.0", "2.3.4"] | ||
}, | ||
"debug": { | ||
"type": "boolean", | ||
"description": "Enable or disable debug mode for the Sentry integration.", | ||
"default": true | ||
}, | ||
"traceSampleRate": { | ||
"type": "number", | ||
"description": "A decimal value between 0 and 1 indicating the percentage of transactions to be sampled for performance monitoring.", | ||
"minimum": 0, | ||
"maximum": 1, | ||
"default": 0.5 | ||
}, | ||
"breadcrumbsLogger": { | ||
"type": "array", | ||
"description": "The loggers to be used for breadcrumbs (e.g., ActiveSupportLogger, HttpLogger).", | ||
"items": { | ||
"type": "string", | ||
"enum": "[active_support_logger http_logger]" | ||
}, | ||
"default": "[active_support_logger http_logger]" | ||
}, | ||
"backgroundWorkerThreads": { | ||
"type": "integer", | ||
"description": "The number of background worker threads for processing.", | ||
"default": 5 | ||
}, | ||
"excludedExceptions": { | ||
"type": "array", | ||
"description": "List of exceptions to be excluded from Sentry reporting.", | ||
"items": { | ||
"type": "string" | ||
}, | ||
"default": [] | ||
} | ||
} | ||
} | ||
} |
7 changes: 7 additions & 0 deletions
7
integrations/lib/multiwoven/integrations/destination/sentry/icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
125 changes: 125 additions & 0 deletions
125
integrations/spec/multiwoven/integrations/sentry/client_spec.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
# frozen_string_literal: true | ||
|
||
RSpec.describe Multiwoven::Integrations::Destination::Sentry::Client do | ||
let(:connection_config) do | ||
{ | ||
dsn: "https://598589589@p458458945894589.ingest.co/45894590549", | ||
environment: "production" | ||
} | ||
end | ||
let(:sync_config) { instance_double("Sync Config", sync_id: 1, sync_run_id: 2) } | ||
let(:records) do | ||
[ | ||
instance_double("valid_standard_error"), | ||
instance_double("valid_argument_error"), | ||
instance_double("valid_activerecord_error"), | ||
instance_double("valid_record_not_found_error") | ||
] | ||
end | ||
|
||
let(:sentry_client) { described_class.new(connection_config) } | ||
|
||
describe "#check_connection" do | ||
context "when successful connection" do | ||
before do | ||
allow(Multiwoven::Integrations::Core::HttpClient).to receive(:request).with( | ||
"p458458945894589.ingest.co", | ||
"POST", | ||
headers: { | ||
"Content-Type" => "application/json", | ||
"X-Sentry-Auth" => "Sentry sentry_version=7, sentry_key=598589589" | ||
} | ||
).and_return({ code: 200 }) | ||
end | ||
|
||
it "returns a successful connection" do | ||
response = sentry_client.check_connection | ||
expect(response).to be_a(Multiwoven::Integrations::Protocol::MultiwovenMessage) | ||
expect(response.connection_status.status).to eq("succeeded") | ||
end | ||
end | ||
|
||
context "when connection fails" do | ||
before do | ||
allow(Multiwoven::Integrations::Core::HttpClient).to receive(:request).with( | ||
"p458458945894589.ingest.co", | ||
"POST", | ||
headers: { | ||
"Content-Type" => "application/json", | ||
"X-Sentry-Auth" => "Sentry sentry_version=7, sentry_key=598589589" | ||
} | ||
).and_return({ code: 404 }) | ||
end | ||
|
||
it "returns a failure status" do | ||
response = sentry_client.check_connection | ||
expect(response).to be_a(Multiwoven::Integrations::Protocol::MultiwovenMessage) | ||
expect(response.connection_status.status).to eq("failed") | ||
end | ||
end | ||
end | ||
|
||
describe "#write" do | ||
context "when successful write" do | ||
it "writes errors to Sentry and handles exceptions" do | ||
expect(sentry_client).to receive(:process_records).with(records) | ||
sentry_client.write(sync_config, records) | ||
end | ||
end | ||
|
||
context "when failure write" do | ||
before do | ||
allow(sentry_client).to receive(:process_records).with(records).and_raise(StandardError) | ||
end | ||
it "raise error on process record" do | ||
expect(sentry_client).to receive(:handle_exception).with( | ||
StandardError, { | ||
context: "SENTRY:WRITE:EXCEPTION", | ||
type: "error", | ||
sync_id: sync_config.sync_id, | ||
sync_run_id: sync_config.sync_run_id | ||
} | ||
) | ||
sentry_client.write(sync_config, records) | ||
end | ||
end | ||
end | ||
|
||
describe "#process_records" do | ||
context "when process records success" do | ||
before do | ||
allow(::Sentry).to receive(:capture_exception) | ||
end | ||
|
||
it "captures sentry exception" do | ||
records.each do |_record| | ||
expect(::Sentry).to receive(:capture_exception) | ||
end | ||
sentry_client.send(:process_records, sync_config, records) | ||
end | ||
end | ||
|
||
context "when process sync fails" do | ||
let(:invalid_records) { [double("InvalidRecord")] } | ||
|
||
before do | ||
allow(::Sentry).to receive(:capture_exception).and_raise(StandardError) | ||
end | ||
|
||
it "handles exceptions raised during processing" do | ||
invalid_records.each do | ||
expect(sentry_client).to receive(:handle_exception).with( | ||
StandardError, { | ||
context: "SENTRY:WRITE:EXCEPTION", | ||
type: "error", | ||
sync_id: sync_config.sync_id, | ||
sync_run_id: sync_config.sync_run_id | ||
} | ||
) | ||
|
||
sentry_client.send(:process_records, sync_config, invalid_records) | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
Sentry.init do |config| | ||
# setup the enviroment | ||
config.enviroment = ENV['RAILS_ENV'] | ||
|
||
end |