forked from e621ng/e621ng
[Prod] Add Datadog
Let's see how this one works out. Cute logo
This commit is contained in:
parent
40ff649250
commit
0b47770c49
14
.env.sample
14
.env.sample
@ -50,7 +50,9 @@
|
|||||||
# The application must have its OAuth2 redirect URI set to ${JOINER_BASE_URL}/callback.
|
# The application must have its OAuth2 redirect URI set to ${JOINER_BASE_URL}/callback.
|
||||||
# You also need to fill out all the JOINER_* environment variables below.
|
# You also need to fill out all the JOINER_* environment variables below.
|
||||||
#
|
#
|
||||||
# COMPOSE_PROFILES=discord
|
# datadog: Start the datadog agent to push performance metrics through ddtrace.
|
||||||
|
# You also need to fill out the DD_API_KEY environment variables below.
|
||||||
|
# COMPOSE_PROFILES=discord,datadog
|
||||||
|
|
||||||
# Change the ports that are forwarded by docker to avoid potential conflicts
|
# Change the ports that are forwarded by docker to avoid potential conflicts
|
||||||
|
|
||||||
@ -64,3 +66,13 @@
|
|||||||
# JOINER_OAUTH2_CLIENT_SECRET=
|
# JOINER_OAUTH2_CLIENT_SECRET=
|
||||||
# JOINER_GUILD_ID=
|
# JOINER_GUILD_ID=
|
||||||
# JOINER_FAILED_JOIN_WEBHOOK_URL=
|
# JOINER_FAILED_JOIN_WEBHOOK_URL=
|
||||||
|
|
||||||
|
# The following environment variables are used when using the 'datadog' profile:
|
||||||
|
|
||||||
|
# Required:
|
||||||
|
# DD_API_KEY=
|
||||||
|
#
|
||||||
|
# Optional:
|
||||||
|
# DD_SITE=us5.datadoghq.com
|
||||||
|
# DD_SERVICE=E6ng (Dev)
|
||||||
|
# DD_ENV=local
|
||||||
|
2
Gemfile
2
Gemfile
@ -35,6 +35,8 @@ gem "rugged"
|
|||||||
# Blocked by unicorn which lacks a release with Rack 3 support
|
# Blocked by unicorn which lacks a release with Rack 3 support
|
||||||
gem "rack", "~> 2.0"
|
gem "rack", "~> 2.0"
|
||||||
|
|
||||||
|
gem "datadog", require: "datadog/auto_instrument"
|
||||||
|
|
||||||
gem 'opensearch-ruby'
|
gem 'opensearch-ruby'
|
||||||
|
|
||||||
gem 'mailgun-ruby'
|
gem 'mailgun-ruby'
|
||||||
|
11
Gemfile.lock
11
Gemfile.lock
@ -115,7 +115,14 @@ GEM
|
|||||||
rexml
|
rexml
|
||||||
crass (1.0.6)
|
crass (1.0.6)
|
||||||
dalli (3.2.6)
|
dalli (3.2.6)
|
||||||
|
datadog (2.0.0.beta1)
|
||||||
|
base64
|
||||||
|
debase-ruby_core_source (= 3.3.1)
|
||||||
|
libdatadog (~> 6.0.0.2.0)
|
||||||
|
libddwaf (~> 1.14.0.0.0)
|
||||||
|
msgpack
|
||||||
date (3.3.4)
|
date (3.3.4)
|
||||||
|
debase-ruby_core_source (3.3.1)
|
||||||
debug (1.9.1)
|
debug (1.9.1)
|
||||||
irb (~> 1.10)
|
irb (~> 1.10)
|
||||||
reline (>= 0.3.8)
|
reline (>= 0.3.8)
|
||||||
@ -163,6 +170,9 @@ GEM
|
|||||||
jsonapi-renderer (0.2.2)
|
jsonapi-renderer (0.2.2)
|
||||||
kgio (2.11.4)
|
kgio (2.11.4)
|
||||||
language_server-protocol (3.17.0.3)
|
language_server-protocol (3.17.0.3)
|
||||||
|
libdatadog (6.0.0.2.0)
|
||||||
|
libddwaf (1.14.0.0.0)
|
||||||
|
ffi (~> 1.0)
|
||||||
listen (3.8.0)
|
listen (3.8.0)
|
||||||
rb-fsevent (~> 0.10, >= 0.10.3)
|
rb-fsevent (~> 0.10, >= 0.10.3)
|
||||||
rb-inotify (~> 0.9, >= 0.9.10)
|
rb-inotify (~> 0.9, >= 0.9.10)
|
||||||
@ -380,6 +390,7 @@ DEPENDENCIES
|
|||||||
bcrypt
|
bcrypt
|
||||||
bootsnap
|
bootsnap
|
||||||
dalli
|
dalli
|
||||||
|
datadog
|
||||||
debug
|
debug
|
||||||
diffy
|
diffy
|
||||||
dotenv
|
dotenv
|
||||||
|
@ -1,20 +1,22 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class DanbooruLogger
|
class DanbooruLogger
|
||||||
def self.log(exception, expected: false, **_params)
|
def self.log(exception, expected: false)
|
||||||
if expected
|
if expected
|
||||||
Rails.logger.info("#{exception.class}: #{exception.message}")
|
Rails.logger.info("#{exception.class}: #{exception.message}")
|
||||||
else
|
else
|
||||||
backtrace = Rails.backtrace_cleaner.clean(exception.backtrace).join("\n")
|
backtrace = Rails.backtrace_cleaner.clean(exception.backtrace).join("\n")
|
||||||
Rails.logger.error("#{exception.class}: #{exception.message}\n#{backtrace}")
|
Rails.logger.error("#{exception.class}: #{exception.message}\n#{backtrace}")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Datadog::Tracing.active_span&.set_error(exception) unless expected
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.initialize(user)
|
def self.initialize(user)
|
||||||
add_attributes("user.id" => user.id, "user.name" => user.name)
|
add_attributes("user.id" => user.id) unless user.is_anonymous?
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.add_attributes(**)
|
def self.add_attributes(**)
|
||||||
# noop
|
Datadog::Tracing.active_span&.set_tags(**)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -217,8 +217,7 @@ class ApplicationRecord < ActiveRecord::Base
|
|||||||
def with_timeout(n, default_value = nil)
|
def with_timeout(n, default_value = nil)
|
||||||
connection.execute("SET STATEMENT_TIMEOUT = #{n}") unless Rails.env == "test"
|
connection.execute("SET STATEMENT_TIMEOUT = #{n}") unless Rails.env == "test"
|
||||||
yield
|
yield
|
||||||
rescue ::ActiveRecord::StatementInvalid => x
|
rescue ::ActiveRecord::StatementInvalid
|
||||||
DanbooruLogger.log(x, expected: true)
|
|
||||||
return default_value
|
return default_value
|
||||||
ensure
|
ensure
|
||||||
connection.execute("SET STATEMENT_TIMEOUT = #{CurrentUser.user.try(:statement_timeout) || 3_000}") unless Rails.env == "test"
|
connection.execute("SET STATEMENT_TIMEOUT = #{CurrentUser.user.try(:statement_timeout) || 3_000}") unless Rails.env == "test"
|
||||||
|
@ -206,8 +206,6 @@ class TagAlias < TagRelationship
|
|||||||
forum_updater.update(failure_message(e), "FAILED") if update_topic
|
forum_updater.update(failure_message(e), "FAILED") if update_topic
|
||||||
update_columns(status: "error: #{e}")
|
update_columns(status: "error: #{e}")
|
||||||
end
|
end
|
||||||
|
|
||||||
DanbooruLogger.log(e, tag_alias_id: id, antecedent_name: antecedent_name, consequent_name: consequent_name)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -138,8 +138,6 @@ class TagImplication < TagRelationship
|
|||||||
|
|
||||||
forum_updater.update(failure_message(e), "FAILED") if update_topic
|
forum_updater.update(failure_message(e), "FAILED") if update_topic
|
||||||
update_columns(status: "error: #{e}")
|
update_columns(status: "error: #{e}")
|
||||||
|
|
||||||
DanbooruLogger.log(e, tag_implication_id: id, antecedent_name: antecedent_name, consequent_name: consequent_name)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
10
config/initializers/01_sensitive_params.rb
Normal file
10
config/initializers/01_sensitive_params.rb
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module SensitiveParams
|
||||||
|
# Common values for Rails and Datadog query parameter filtering
|
||||||
|
PARAMS = %i[passw secret token _key crypt salt certificate otp ssn email].freeze
|
||||||
|
|
||||||
|
def self.to_datadog_regex
|
||||||
|
Regexp.new("(?:#{PARAMS.join('|')})[^&]*=[^&]*")
|
||||||
|
end
|
||||||
|
end
|
14
config/initializers/datadog.rb
Normal file
14
config/initializers/datadog.rb
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
Datadog.configure do |c|
|
||||||
|
c.tracing.enabled = !Rails.env.test? && ENV["DD_API_KEY"].present?
|
||||||
|
c.logger.level = Logger::WARN
|
||||||
|
|
||||||
|
c.tracing.instrument :rack, quantize: {
|
||||||
|
query: {
|
||||||
|
obfuscate: {
|
||||||
|
regex: SensitiveParams.to_datadog_regex,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
end
|
@ -5,6 +5,4 @@
|
|||||||
# Configure parameters to be partially matched (e.g. passw matches password) and filtered from the log file.
|
# Configure parameters to be partially matched (e.g. passw matches password) and filtered from the log file.
|
||||||
# Use this to limit dissemination of sensitive information.
|
# Use this to limit dissemination of sensitive information.
|
||||||
# See the ActiveSupport::ParameterFilter documentation for supported notations and behaviors.
|
# See the ActiveSupport::ParameterFilter documentation for supported notations and behaviors.
|
||||||
Rails.application.config.filter_parameters += [
|
Rails.application.config.filter_parameters += SensitiveParams::PARAMS
|
||||||
:passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn, :email
|
|
||||||
]
|
|
||||||
|
@ -15,6 +15,7 @@ x-environment: &common-env
|
|||||||
SESSION_SECRET_KEY: 44b4f44e9f253c406cbe727d403d500c1cecff943e4d2aea8f5447f28846fffe
|
SESSION_SECRET_KEY: 44b4f44e9f253c406cbe727d403d500c1cecff943e4d2aea8f5447f28846fffe
|
||||||
# Hide annoying output from libvips on corrupt files
|
# Hide annoying output from libvips on corrupt files
|
||||||
VIPS_WARNING: "0"
|
VIPS_WARNING: "0"
|
||||||
|
DD_TRACE_STARTUP_LOGS: false
|
||||||
|
|
||||||
x-depends-on: &common-depends-on
|
x-depends-on: &common-depends-on
|
||||||
opensearch:
|
opensearch:
|
||||||
@ -43,6 +44,9 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
<<: *common-env
|
<<: *common-env
|
||||||
RAILS_ENV: development
|
RAILS_ENV: development
|
||||||
|
DD_AGENT_HOST: datadog-agent
|
||||||
|
DD_SERVICE: ${DD_SERVICE:-}
|
||||||
|
DD_ENV: ${DD_ENV:-}
|
||||||
depends_on:
|
depends_on:
|
||||||
<<: *common-depends-on
|
<<: *common-depends-on
|
||||||
autocompleted:
|
autocompleted:
|
||||||
@ -118,6 +122,17 @@ services:
|
|||||||
command: iqdb http 0.0.0.0 5588 /iqdb/e621_v2.db
|
command: iqdb http 0.0.0.0 5588 /iqdb/e621_v2.db
|
||||||
volumes:
|
volumes:
|
||||||
- iqdb_data:/iqdb
|
- iqdb_data:/iqdb
|
||||||
|
|
||||||
|
datadog-agent:
|
||||||
|
image: datadog/agent:7.52.0
|
||||||
|
environment:
|
||||||
|
DD_API_KEY: ${DD_API_KEY:-}
|
||||||
|
DD_SITE: ${DD_SITE:-us5.datadoghq.com}
|
||||||
|
DD_HOSTNAME: datadog-agent
|
||||||
|
DD_LOG_LEVEL: WARN
|
||||||
|
DD_APM_NON_LOCAL_TRAFFIC: true
|
||||||
|
profiles:
|
||||||
|
- datadog
|
||||||
|
|
||||||
# Discord integration
|
# Discord integration
|
||||||
|
|
||||||
|
25
test/unit/datadog_test.rb
Normal file
25
test/unit/datadog_test.rb
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "test_helper"
|
||||||
|
|
||||||
|
class DatadogTest < ActiveSupport::TestCase
|
||||||
|
def assert_match_group(expected, query)
|
||||||
|
assert_equal(expected, query[SensitiveParams.to_datadog_regex])
|
||||||
|
end
|
||||||
|
|
||||||
|
def assert_no_match_group(query)
|
||||||
|
assert_nil(query[SensitiveParams.to_datadog_regex])
|
||||||
|
end
|
||||||
|
|
||||||
|
should "filters query parameters" do
|
||||||
|
assert_match_group("password=hunter2", "password=hunter2")
|
||||||
|
assert_match_group("password=hunter2", "?abc=def&password=hunter2&foo=bar")
|
||||||
|
# These partial matches are fine, just don't let datadog grab it
|
||||||
|
assert_match_group("password]=hunter2", "?abc=def&user[password]=hunter2&foo=bar")
|
||||||
|
assert_match_group("password=hunter2", "old_password=hunter2")
|
||||||
|
assert_match_group("password_old=hunter2", "password_old=hunter2")
|
||||||
|
|
||||||
|
assert_no_match_group("something=else")
|
||||||
|
assert_no_match_group("search[foo]=bar")
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue
Block a user