2021-06-08 01:23:25 +05:30
# frozen_string_literal: true
module Integrations
class Datadog < Integration
2021-09-30 23:02:18 +05:30
include HasWebHook
DEFAULT_DOMAIN = 'datadoghq.com'
2021-11-11 11:23:49 +05:30
URL_TEMPLATE = 'https://webhook-intake.%{datadog_domain}/api/v2/webhook'
2021-09-30 23:02:18 +05:30
URL_API_KEYS_DOCS = " https://docs. #{ DEFAULT_DOMAIN } /account_management/api-app-keys/ "
2021-06-08 01:23:25 +05:30
SUPPORTED_EVENTS = %w[
2023-03-04 22:38:38 +05:30
pipeline build archive_trace
2021-06-08 01:23:25 +05:30
] . freeze
2022-04-04 11:22:00 +05:30
TAG_KEY_VALUE_RE = %r{ \ A [ \ w-]+ : .* \ S.* \ z }x . freeze
2022-11-25 23:54:43 +05:30
field :datadog_site ,
2023-03-04 22:38:38 +05:30
exposes_secrets : true ,
2022-11-25 23:54:43 +05:30
placeholder : DEFAULT_DOMAIN ,
help : - > do
ERB :: Util . html_escape (
s_ ( 'DatadogIntegration|The Datadog site to send data to. To send data to the EU site, use %{codeOpen}datadoghq.eu%{codeClose}.' )
) % {
codeOpen : '<code>' . html_safe ,
codeClose : '</code>' . html_safe
}
end
field :api_url ,
exposes_secrets : true ,
title : - > { s_ ( 'DatadogIntegration|API URL' ) } ,
help : - > { s_ ( 'DatadogIntegration|(Advanced) The full URL for your Datadog site.' ) }
field :api_key ,
type : 'password' ,
title : - > { _ ( 'API key' ) } ,
non_empty_password_title : - > { s_ ( 'ProjectService|Enter new API key' ) } ,
non_empty_password_help : - > { s_ ( 'ProjectService|Leave blank to use your current API key' ) } ,
help : - > do
ERB :: Util . html_escape (
s_ ( 'DatadogIntegration|%{linkOpen}API key%{linkClose} used for authentication with Datadog.' )
) % {
linkOpen : %Q{ <a href=" #{ URL_API_KEYS_DOCS } " target="_blank" rel="noopener noreferrer"> } . html_safe ,
linkClose : '</a>' . html_safe
}
end ,
required : true
field :archive_trace_events ,
storage : :attribute ,
type : 'checkbox' ,
2023-03-04 22:38:38 +05:30
title : - > { _ ( 'Logs' ) } ,
checkbox_label : - > { _ ( 'Enable logs collection' ) } ,
2022-11-25 23:54:43 +05:30
help : - > { s_ ( 'When enabled, job logs are collected by Datadog and displayed along with pipeline execution traces.' ) }
field :datadog_service ,
title : - > { s_ ( 'DatadogIntegration|Service' ) } ,
placeholder : 'gitlab-ci' ,
help : - > { s_ ( 'DatadogIntegration|Tag all data from this GitLab instance in Datadog. Useful when managing several self-managed deployments.' ) }
field :datadog_env ,
title : - > { s_ ( 'DatadogIntegration|Environment' ) } ,
placeholder : 'ci' ,
help : - > do
ERB :: Util . html_escape (
s_ ( 'DatadogIntegration|For self-managed deployments, set the %{codeOpen}env%{codeClose} tag for all the data sent to Datadog. %{linkOpen}How do I use tags?%{linkClose}' )
) % {
codeOpen : '<code>' . html_safe ,
codeClose : '</code>' . html_safe ,
linkOpen : '<a href="https://docs.datadoghq.com/getting_started/tagging/#using-tags" target="_blank" rel="noopener noreferrer">' . html_safe ,
linkClose : '</a>' . html_safe
}
end
field :datadog_tags ,
type : 'textarea' ,
title : - > { s_ ( 'DatadogIntegration|Tags' ) } ,
placeholder : " tag:value \n another_tag:value " ,
help : - > do
ERB :: Util . html_escape (
s_ ( 'DatadogIntegration|Custom tags in Datadog. Enter one tag per line in the %{codeOpen}key:value%{codeClose} format. %{linkOpen}How do I use tags?%{linkClose}' )
) % {
codeOpen : '<code>' . html_safe ,
codeClose : '</code>' . html_safe ,
linkOpen : '<a href="https://docs.datadoghq.com/getting_started/tagging/#using-tags" target="_blank" rel="noopener noreferrer">' . html_safe ,
linkClose : '</a>' . html_safe
}
end
2022-04-04 11:22:00 +05:30
before_validation :strip_properties
2021-06-08 01:23:25 +05:30
with_options if : :activated? do
validates :api_key , presence : true , format : { with : / \ A \ w+ \ z / }
2023-01-13 00:05:48 +05:30
validates :datadog_site , format : { with : %r{ \ A \ w+([-.] \ w+)* \ .[a-zA-Z] { 2,5 } (:[0-9] { 1,5 } )? \ z } , allow_blank : true }
2021-06-08 01:23:25 +05:30
validates :api_url , public_url : { allow_blank : true }
validates :datadog_site , presence : true , unless : - > ( obj ) { obj . api_url . present? }
validates :api_url , presence : true , unless : - > ( obj ) { obj . datadog_site . present? }
2022-04-04 11:22:00 +05:30
validate :datadog_tags_are_valid
2021-06-08 01:23:25 +05:30
end
def initialize_properties
super
2021-09-30 23:02:18 +05:30
self . datadog_site || = DEFAULT_DOMAIN
2021-06-08 01:23:25 +05:30
end
def self . supported_events
SUPPORTED_EVENTS
end
def self . default_test_event
'pipeline'
end
def configurable_events
[ ] # do not allow to opt out of required hooks
2022-03-02 08:16:31 +05:30
# archive_trace is opt-in but we handle it with a more detailed field below
2021-06-08 01:23:25 +05:30
end
def title
'Datadog'
end
def description
2021-10-27 15:23:28 +05:30
s_ ( 'DatadogIntegration|Trace your GitLab pipelines with Datadog.' )
2021-06-08 01:23:25 +05:30
end
def help
2022-03-02 08:16:31 +05:30
docs_link = ActionController :: Base . helpers . link_to (
s_ ( 'DatadogIntegration|How do I set up this integration?' ) ,
Rails . application . routes . url_helpers . help_page_url ( 'integration/datadog' ) ,
target : '_blank' , rel : 'noopener noreferrer'
)
2021-10-27 15:23:28 +05:30
s_ ( 'DatadogIntegration|Send CI/CD pipeline information to Datadog to monitor for job failures and troubleshoot performance issues. %{docs_link}' ) . html_safe % { docs_link : docs_link . html_safe }
2021-06-08 01:23:25 +05:30
end
def self . to_param
'datadog'
end
2021-09-30 23:02:18 +05:30
override :hook_url
2021-06-08 01:23:25 +05:30
def hook_url
2021-09-30 23:02:18 +05:30
url = api_url . presence || sprintf ( URL_TEMPLATE , datadog_domain : datadog_domain )
2021-06-08 01:23:25 +05:30
url = URI . parse ( url )
2021-09-30 23:02:18 +05:30
query = {
2022-10-02 17:18:49 +05:30
" dd-api-key " = > 'THIS_VALUE_WILL_BE_REPLACED' ,
2021-09-30 23:02:18 +05:30
service : datadog_service . presence ,
2022-04-04 11:22:00 +05:30
env : datadog_env . presence ,
tags : datadog_tags_query_param . presence
2021-09-30 23:02:18 +05:30
} . compact
url . query = query . to_query
2022-10-02 17:18:49 +05:30
url . to_s . gsub ( 'THIS_VALUE_WILL_BE_REPLACED' , '{api_key}' )
end
def url_variables
{ 'api_key' = > api_key }
2021-06-08 01:23:25 +05:30
end
def execute ( data )
2023-03-04 22:38:38 +05:30
return unless supported_events . include? ( data [ :object_kind ] )
2021-06-08 01:23:25 +05:30
object_kind = data [ :object_kind ]
object_kind = 'job' if object_kind == 'build'
2022-03-02 08:16:31 +05:30
data = hook_data ( data , object_kind )
2021-09-30 23:02:18 +05:30
execute_web_hook! ( data , " #{ object_kind } hook " )
2021-06-08 01:23:25 +05:30
end
def test ( data )
2021-10-27 15:23:28 +05:30
result = execute ( data )
{
2023-01-13 00:05:48 +05:30
success : ( 200 .. 299 ) . cover? ( result . payload [ :http_status ] ) ,
result : result . message
2021-10-27 15:23:28 +05:30
}
2021-06-08 01:23:25 +05:30
end
2021-09-30 23:02:18 +05:30
private
def datadog_domain
# Transparently ignore "app" prefix from datadog_site as the official docs table in
# https://docs.datadoghq.com/getting_started/site/ is confusing for internal URLs.
# US3 needs to keep a prefix but other datacenters cannot have the listed "app" prefix
datadog_site . delete_prefix ( " app. " )
end
2022-03-02 08:16:31 +05:30
def hook_data ( data , object_kind )
if object_kind == 'pipeline' && data . respond_to? ( :with_retried_builds )
return data . with_retried_builds
end
data
end
2022-04-04 11:22:00 +05:30
def strip_properties
datadog_service . strip! if datadog_service && ! datadog_service . frozen?
datadog_env . strip! if datadog_env && ! datadog_env . frozen?
datadog_tags . strip! if datadog_tags && ! datadog_tags . frozen?
end
def datadog_tags_are_valid
return unless datadog_tags
unless datadog_tags . split ( " \n " ) . select ( & :present? ) . all? { _1 =~ TAG_KEY_VALUE_RE }
errors . add ( :datadog_tags , s_ ( " DatadogIntegration|have an invalid format " ) )
end
end
def datadog_tags_query_param
return unless datadog_tags
datadog_tags . split ( " \n " ) . filter_map do | tag |
tag . strip!
next if tag . blank?
if tag . include? ( ',' )
" \" #{ tag } \" "
else
tag
end
end . join ( ',' )
end
2021-06-08 01:23:25 +05:30
end
end