From eda52930be6e10c61d444a18fe789de933f69a58 Mon Sep 17 00:00:00 2001 From: Sojan Jose Date: Thu, 15 Jul 2021 23:58:54 +0530 Subject: [PATCH] chore: Add Telemetry (#2631) ref: https://www.chatwoot.com/docs/self-hosted/telemetry --- .../installation/onboarding_controller.rb | 8 ++- lib/chatwoot_hub.rb | 48 +++++++++++-- spec/lib/chatwoot_hub_spec.rb | 72 ++++++++++++++++--- 3 files changed, 113 insertions(+), 15 deletions(-) diff --git a/app/controllers/installation/onboarding_controller.rb b/app/controllers/installation/onboarding_controller.rb index a6f04238b..130938fd8 100644 --- a/app/controllers/installation/onboarding_controller.rb +++ b/app/controllers/installation/onboarding_controller.rb @@ -27,7 +27,13 @@ class Installation::OnboardingController < ApplicationController def finish_onboarding ::Redis::Alfred.delete(::Redis::Alfred::CHATWOOT_INSTALLATION_ONBOARDING) - ChatwootHub.register_instance(onboarding_params) if onboarding_params[:subscribe_to_updates] + return if onboarding_params[:subscribe_to_updates].blank? + + ChatwootHub.register_instance( + onboarding_params.dig(:user, :company), + onboarding_params.dig(:user, :name), + onboarding_params.dig(:user, :email) + ) end def ensure_installation_onboarding diff --git a/lib/chatwoot_hub.rb b/lib/chatwoot_hub.rb index ef500e57b..2de8f5d30 100644 --- a/lib/chatwoot_hub.rb +++ b/lib/chatwoot_hub.rb @@ -1,16 +1,40 @@ class ChatwootHub - BASE_URL = ENV['CHATWOOT_HUB_URL'] || 'https://hub.chatwoot.com' + BASE_URL = ENV['CHATWOOT_HUB_URL'] || 'https://hub.2.chatwoot.com' + PING_URL = "#{BASE_URL}/ping".freeze + REGISTRATION_URL = "#{BASE_URL}/instances".freeze + EVENTS_URL = "#{BASE_URL}/events".freeze + + def self.installation_identifier + identifier = InstallationConfig.find_by(name: 'INSTALLATION_IDENTIFIER')&.value + identifier ||= InstallationConfig.create(name: 'INSTALLATION_IDENTIFIER', value: SecureRandom.uuid).value + identifier + end def self.instance_config { - installationVersion: Chatwoot.config[:version], - installationHost: URI.parse(ENV.fetch('FRONTEND_URL', '')).host + installation_identifier: installation_identifier, + installation_version: Chatwoot.config[:version], + installation_host: URI.parse(ENV.fetch('FRONTEND_URL', '')).host + } + end + + def self.instance_metrics + { + accounts_count: Account.count, + users_count: User.count, + inboxes_count: Inbox.count, + conversations_count: Conversation.count, + incoming_messages_count: Message.incoming.count, + outgoing_messages_count: Message.outgoing.count, + additional_information: {} } end def self.latest_version begin - response = RestClient.get(BASE_URL, { params: instance_config }) + info = instance_config + info = info.merge(instance_metrics) unless ENV['DISABLE_TELEMETRY'] + response = RestClient.post(PING_URL, info.to_json, { content_type: :json, accept: :json }) version = JSON.parse(response)['version'] rescue *ExceptionList::REST_CLIENT_EXCEPTIONS, *ExceptionList::URI_EXCEPTIONS => e Rails.logger.info "Exception: #{e.message}" @@ -20,8 +44,20 @@ class ChatwootHub version end - def self.register_instance(info) - RestClient.post("#{BASE_URL}/register_instance", info.merge(instance_config).to_json, { content_type: :json, accept: :json }) + def self.register_instance(company_name, owner_name, owner_email) + info = { company_name: company_name, owner_name: owner_name, owner_email: owner_email, subscribed_to_mailers: true } + RestClient.post(REGISTRATION_URL, info.merge(instance_config).to_json, { content_type: :json, accept: :json }) + rescue *ExceptionList::REST_CLIENT_EXCEPTIONS, *ExceptionList::URI_EXCEPTIONS => e + Rails.logger.info "Exception: #{e.message}" + rescue StandardError => e + Raven.capture_exception(e) + end + + def self.emit_event(event_name, event_data) + return if ENV['DISABLE_TELEMETRY'] + + info = { event_name: event_name, event_data: event_data } + RestClient.post(EVENTS_URL, info.merge(instance_config).to_json, { content_type: :json, accept: :json }) rescue *ExceptionList::REST_CLIENT_EXCEPTIONS, *ExceptionList::URI_EXCEPTIONS => e Rails.logger.info "Exception: #{e.message}" rescue StandardError => e diff --git a/spec/lib/chatwoot_hub_spec.rb b/spec/lib/chatwoot_hub_spec.rb index 2cd5c6be1..e42feee95 100644 --- a/spec/lib/chatwoot_hub_spec.rb +++ b/spec/lib/chatwoot_hub_spec.rb @@ -1,15 +1,71 @@ require 'rails_helper' describe ChatwootHub do - it 'get latest version from chatwoot hub' do - version = '1.1.1' - allow(RestClient).to receive(:get).and_return({ version: version }.to_json) - expect(described_class.latest_version).to eq version - expect(RestClient).to have_received(:get).with(described_class::BASE_URL, { params: described_class.instance_config }) + it 'generates installation identifier' do + installation_identifier = described_class.installation_identifier + expect(installation_identifier).not_to eq nil + expect(described_class.installation_identifier).to eq installation_identifier end - it 'returns nil when chatwoot hub is down' do - allow(RestClient).to receive(:get).and_raise(ExceptionList::REST_CLIENT_EXCEPTIONS.sample) - expect(described_class.latest_version).to eq nil + context 'when fetching latest_version' do + it 'get latest version from chatwoot hub' do + version = '1.1.1' + allow(RestClient).to receive(:post).and_return({ version: version }.to_json) + expect(described_class.latest_version).to eq version + expect(RestClient).to have_received(:post).with(described_class::PING_URL, described_class.instance_config + .merge(described_class.instance_metrics).to_json, { content_type: :json, accept: :json }) + end + + it 'will not send instance metrics when telemetry is disabled' do + version = '1.1.1' + ENV['DISABLE_TELEMETRY'] = 'true' + allow(RestClient).to receive(:post).and_return({ version: version }.to_json) + expect(described_class.latest_version).to eq version + expect(RestClient).to have_received(:post).with(described_class::PING_URL, + described_class.instance_config.to_json, { content_type: :json, accept: :json }) + ENV['DISABLE_TELEMETRY'] = nil + end + + it 'returns nil when chatwoot hub is down' do + allow(RestClient).to receive(:post).and_raise(ExceptionList::REST_CLIENT_EXCEPTIONS.sample) + expect(described_class.latest_version).to eq nil + end + end + + context 'when register instance' do + let(:company_name) { 'test' } + let(:owner_name) { 'test' } + let(:owner_email) { 'test@test.com' } + + it 'sends info of registration' do + info = { company_name: company_name, owner_name: owner_name, owner_email: owner_email, subscribed_to_mailers: true } + allow(RestClient).to receive(:post) + described_class.register_instance(company_name, owner_name, owner_email) + expect(RestClient).to have_received(:post).with(described_class::REGISTRATION_URL, + info.merge(described_class.instance_config).to_json, { content_type: :json, accept: :json }) + end + end + + context 'when sending events' do + let(:event_name) { 'sample_event' } + let(:event_data) { { 'sample_data' => 'sample_data' } } + + it 'will send instance events' do + info = { event_name: event_name, event_data: event_data } + allow(RestClient).to receive(:post) + described_class.emit_event(event_name, event_data) + expect(RestClient).to have_received(:post).with(described_class::EVENTS_URL, + info.merge(described_class.instance_config).to_json, { content_type: :json, accept: :json }) + end + + it 'will not send instance events when telemetry is disabled' do + ENV['DISABLE_TELEMETRY'] = 'true' + info = { event_name: event_name, event_data: event_data } + allow(RestClient).to receive(:post) + described_class.emit_event(event_name, event_data) + expect(RestClient).not_to have_received(:post).with(described_class::EVENTS_URL, + info.merge(described_class.instance_config).to_json, { content_type: :json, accept: :json }) + ENV['DISABLE_TELEMETRY'] = nil + end end end