9
9
import traceback
10
10
from collections import defaultdict
11
11
from contextlib import closing , contextmanager
12
+ from string import Template
12
13
from typing import Any , Dict , List , Optional # noqa: F401
13
14
14
15
import pymysql
@@ -109,11 +110,13 @@ def __init__(self, name, init_config, instances):
109
110
self .version = None
110
111
self .is_mariadb = None
111
112
self ._resolved_hostname = None
113
+ self ._database_identifier = None
112
114
self ._agent_hostname = None
113
115
self ._database_hostname = None
114
116
self ._is_aurora = None
115
117
self ._config = MySQLConfig (self .instance , init_config )
116
118
self .tags = self ._config .tags
119
+ self .add_core_tags ()
117
120
self .cloud_metadata = self ._config .cloud_metadata
118
121
119
122
# Create a new connection on every check run
@@ -157,15 +160,46 @@ def _send_metadata(self):
157
160
self .set_metadata ('flavor' , self .version .flavor )
158
161
self .set_metadata ('resolved_hostname' , self .resolved_hostname )
159
162
163
+ @property
164
+ def reported_hostname (self ):
165
+ # type: () -> str
166
+ if self ._config .empty_default_hostname :
167
+ return None
168
+ return self .resolved_hostname
169
+
160
170
@property
161
171
def resolved_hostname (self ):
172
+ # type: () -> str
162
173
if self ._resolved_hostname is None :
163
174
if self ._config .reported_hostname :
164
175
self ._resolved_hostname = self ._config .reported_hostname
165
176
else :
166
177
self ._resolved_hostname = self .resolve_db_host ()
167
178
return self ._resolved_hostname
168
179
180
+ @property
181
+ def database_identifier (self ):
182
+ # type: () -> str
183
+ if self ._database_identifier is None :
184
+ template = Template (self ._config .database_identifier .get ('template' ) or '$resolved_hostname' )
185
+ tag_dict = {}
186
+ tags = self .tags .copy ()
187
+ # sort tags to ensure consistent ordering
188
+ tags .sort ()
189
+ for t in tags :
190
+ if ':' in t :
191
+ key , value = t .split (':' , 1 )
192
+ if key in tag_dict :
193
+ tag_dict [key ] += f",{ value } "
194
+ else :
195
+ tag_dict [key ] = value
196
+ tag_dict ['resolved_hostname' ] = self .resolved_hostname
197
+ tag_dict ['host' ] = str (self ._config .host )
198
+ tag_dict ['port' ] = str (self ._config .port )
199
+ tag_dict ['mysql_sock' ] = str (self ._config .mysql_sock )
200
+ self ._database_identifier = template .safe_substitute (** tag_dict )
201
+ return self ._database_identifier
202
+
169
203
@property
170
204
def agent_hostname (self ):
171
205
# type: () -> str
@@ -180,9 +214,14 @@ def database_hostname(self):
180
214
self ._database_hostname = self .resolve_db_host ()
181
215
return self ._database_hostname
182
216
183
- def set_resource_tags (self ):
217
+ def add_core_tags (self ):
218
+ """
219
+ Add tags that should be attached to every metric/event but which require check calculations outside the config.
220
+ """
184
221
self .tags .append ("database_hostname:{}" .format (self .database_hostname ))
222
+ self .tags .append ("database_instance:{}" .format (self .database_identifier ))
185
223
224
+ def set_resource_tags (self ):
186
225
if self .cloud_metadata .get ("gcp" ) is not None :
187
226
self .tags .append (
188
227
"dd.internal.resource:gcp_sql_database_instance:{}:{}" .format (
@@ -199,6 +238,9 @@ def set_resource_tags(self):
199
238
# allow for detecting if the host is an RDS host, and emit
200
239
# the resource properly even if the `aws` config is unset
201
240
self .tags .append ("dd.internal.resource:aws_rds_instance:{}" .format (self .resolved_hostname ))
241
+ self .cloud_metadata ["aws" ] = {
242
+ "instance_endpoint" : self .resolved_hostname ,
243
+ }
202
244
if self .cloud_metadata .get ("azure" ) is not None :
203
245
deployment_type = self .cloud_metadata .get ("azure" )["deployment_type" ]
204
246
# some `deployment_type`s map to multiple `resource_type`s
@@ -210,7 +252,7 @@ def set_resource_tags(self):
210
252
# finally, emit a `database_instance` resource for this instance
211
253
self .tags .append (
212
254
"dd.internal.resource:database_instance:{}" .format (
213
- self .resolved_hostname ,
255
+ self .database_identifier ,
214
256
)
215
257
)
216
258
@@ -371,7 +413,7 @@ def _new_query_executor(self, queries):
371
413
self .execute_query_raw ,
372
414
self ,
373
415
queries = queries ,
374
- hostname = self .resolved_hostname ,
416
+ hostname = self .reported_hostname ,
375
417
track_operation_time = True ,
376
418
)
377
419
@@ -467,12 +509,12 @@ def _connect(self):
467
509
self .log .debug ("Connected to MySQL" )
468
510
self .service_check_tags = list (set (service_check_tags ))
469
511
self .service_check (
470
- self .SERVICE_CHECK_NAME , AgentCheck .OK , tags = service_check_tags , hostname = self .resolved_hostname
512
+ self .SERVICE_CHECK_NAME , AgentCheck .OK , tags = service_check_tags , hostname = self .reported_hostname
471
513
)
472
514
yield db
473
515
except Exception :
474
516
self .service_check (
475
- self .SERVICE_CHECK_NAME , AgentCheck .CRITICAL , tags = service_check_tags , hostname = self .resolved_hostname
517
+ self .SERVICE_CHECK_NAME , AgentCheck .CRITICAL , tags = service_check_tags , hostname = self .reported_hostname
476
518
)
477
519
raise
478
520
finally :
@@ -796,20 +838,20 @@ def _submit_replication_status(self, status, additional_tags):
796
838
name = self .SLAVE_SERVICE_CHECK_NAME ,
797
839
value = 1 if status == AgentCheck .OK else 0 ,
798
840
tags = self .tags + additional_tags ,
799
- hostname = self .resolved_hostname ,
841
+ hostname = self .reported_hostname ,
800
842
)
801
843
# deprecated in favor of service_check("mysql.replication.replica_running")
802
844
self .service_check (
803
845
self .SLAVE_SERVICE_CHECK_NAME ,
804
846
status ,
805
847
tags = self .service_check_tags + additional_tags ,
806
- hostname = self .resolved_hostname ,
848
+ hostname = self .reported_hostname ,
807
849
)
808
850
self .service_check (
809
851
self .REPLICA_SERVICE_CHECK_NAME ,
810
852
status ,
811
853
tags = self .service_check_tags + additional_tags ,
812
- hostname = self .resolved_hostname ,
854
+ hostname = self .reported_hostname ,
813
855
)
814
856
815
857
def _is_source_host (self , replicas , results ):
@@ -858,13 +900,13 @@ def __submit_metric(self, metric_name, metric_type, variable, db_results, tags):
858
900
metric_tags .append (tag )
859
901
if value is not None :
860
902
if metric_type == RATE :
861
- self .rate (metric_name , value , tags = metric_tags , hostname = self .resolved_hostname )
903
+ self .rate (metric_name , value , tags = metric_tags , hostname = self .reported_hostname )
862
904
elif metric_type == GAUGE :
863
- self .gauge (metric_name , value , tags = metric_tags , hostname = self .resolved_hostname )
905
+ self .gauge (metric_name , value , tags = metric_tags , hostname = self .reported_hostname )
864
906
elif metric_type == COUNT :
865
- self .count (metric_name , value , tags = metric_tags , hostname = self .resolved_hostname )
907
+ self .count (metric_name , value , tags = metric_tags , hostname = self .reported_hostname )
866
908
elif metric_type == MONOTONIC :
867
- self .monotonic_count (metric_name , value , tags = metric_tags , hostname = self .resolved_hostname )
909
+ self .monotonic_count (metric_name , value , tags = metric_tags , hostname = self .reported_hostname )
868
910
869
911
def _collect_dict (self , metric_type , field_metric_map , query , db , tags ):
870
912
"""
@@ -891,15 +933,15 @@ def _collect_dict(self, metric_type, field_metric_map, query, db, tags):
891
933
self .log .debug ("Collecting done, value %s" , result [col_idx ])
892
934
if metric_type == GAUGE :
893
935
self .gauge (
894
- metric , float (result [col_idx ]), tags = tags , hostname = self .resolved_hostname
936
+ metric , float (result [col_idx ]), tags = tags , hostname = self .reported_hostname
895
937
)
896
938
elif metric_type == RATE :
897
939
self .rate (
898
- metric , float (result [col_idx ]), tags = tags , hostname = self .resolved_hostname
940
+ metric , float (result [col_idx ]), tags = tags , hostname = self .reported_hostname
899
941
)
900
942
else :
901
943
self .gauge (
902
- metric , float (result [col_idx ]), tags = tags , hostname = self .resolved_hostname
944
+ metric , float (result [col_idx ]), tags = tags , hostname = self .reported_hostname
903
945
)
904
946
else :
905
947
self .log .debug ("Received value is None for index %d" , col_idx )
@@ -956,10 +998,10 @@ def _collect_system_metrics(self, host, db, tags):
956
998
scpu = proc .cpu_times ()[1 ]
957
999
958
1000
if ucpu and scpu :
959
- self .rate ("mysql.performance.user_time" , ucpu , tags = tags , hostname = self .resolved_hostname )
1001
+ self .rate ("mysql.performance.user_time" , ucpu , tags = tags , hostname = self .reported_hostname )
960
1002
# should really be system_time
961
- self .rate ("mysql.performance.kernel_time" , scpu , tags = tags , hostname = self .resolved_hostname )
962
- self .rate ("mysql.performance.cpu_time" , ucpu + scpu , tags = tags , hostname = self .resolved_hostname )
1003
+ self .rate ("mysql.performance.kernel_time" , scpu , tags = tags , hostname = self .reported_hostname )
1004
+ self .rate ("mysql.performance.cpu_time" , ucpu + scpu , tags = tags , hostname = self .reported_hostname )
963
1005
else :
964
1006
self .log .debug ("psutil is not available, will not collect mysql.performance.* metrics" )
965
1007
except Exception :
@@ -1334,10 +1376,11 @@ def _report_warnings(self):
1334
1376
self .warning (warning )
1335
1377
1336
1378
def _send_database_instance_metadata (self ):
1337
- if self .resolved_hostname not in self ._database_instance_emitted :
1379
+ if self .database_identifier not in self ._database_instance_emitted :
1338
1380
event = {
1339
- "host" : self .resolved_hostname ,
1381
+ "host" : self .reported_hostname ,
1340
1382
"port" : self ._config .port ,
1383
+ "database_instance" : self .database_identifier ,
1341
1384
"database_hostname" : self .database_hostname ,
1342
1385
"agent_version" : datadog_agent .get_version (),
1343
1386
"dbms" : "mysql" ,
@@ -1353,5 +1396,5 @@ def _send_database_instance_metadata(self):
1353
1396
"connection_host" : self ._config .host ,
1354
1397
},
1355
1398
}
1356
- self ._database_instance_emitted [self .resolved_hostname ] = event
1399
+ self ._database_instance_emitted [self .database_identifier ] = event
1357
1400
self .database_monitoring_metadata (json .dumps (event , default = default_json_event_encoding ))
0 commit comments