11# Copyright The OpenTelemetry Authors
22# SPDX-License-Identifier: Apache-2.0
33
4+ import contextlib
45from unittest import mock
56
67import mysql .connector
78
89import opentelemetry .instrumentation .mysql
910from opentelemetry import trace as trace_api
11+ from opentelemetry .instrumentation ._semconv import (
12+ OTEL_SEMCONV_STABILITY_OPT_IN ,
13+ _OpenTelemetrySemanticConventionStability ,
14+ )
1015from opentelemetry .instrumentation .mysql import MySQLInstrumentor
1116from opentelemetry .sdk import resources
1217from opentelemetry .semconv ._incubating .attributes .db_attributes import (
18+ DB_NAME ,
1319 DB_STATEMENT ,
20+ DB_SYSTEM ,
21+ DB_USER ,
22+ )
23+ from opentelemetry .semconv ._incubating .attributes .net_attributes import (
24+ NET_PEER_NAME ,
25+ NET_PEER_PORT ,
26+ )
27+ from opentelemetry .semconv .attributes .db_attributes import (
28+ DB_NAMESPACE ,
29+ DB_QUERY_TEXT ,
30+ DB_SYSTEM_NAME ,
31+ )
32+ from opentelemetry .semconv .attributes .server_attributes import (
33+ SERVER_ADDRESS ,
34+ SERVER_PORT ,
1435)
1536from opentelemetry .test .test_base import TestBase
1637
1738
39+ @contextlib .contextmanager
40+ def use_semconv_opt_in (sem_conv_mode ):
41+ env_patch = mock .patch .dict (
42+ "os.environ" ,
43+ {OTEL_SEMCONV_STABILITY_OPT_IN : sem_conv_mode },
44+ )
45+ _OpenTelemetrySemanticConventionStability ._initialized = False
46+ env_patch .start ()
47+ try :
48+ yield
49+ finally :
50+ env_patch .stop ()
51+ _OpenTelemetrySemanticConventionStability ._initialized = False
52+
53+
1854def connect_and_execute_query ():
1955 cnx = mysql .connector .connect (database = "test" )
2056 cursor = cnx .cursor ()
@@ -29,6 +65,7 @@ def make_mysql_connection_mock():
2965 cnx .database = "test"
3066 cnx .server_host = "localhost"
3167 cnx .server_port = 3306
68+ cnx .user = "testuser"
3269
3370 cursor = mock .MagicMock ()
3471 cursor ._cnx = cnx
@@ -441,3 +478,59 @@ def test_uninstrument_connection(self, mock_connect):
441478
442479 spans_list = self .memory_exporter .get_finished_spans ()
443480 self .assertEqual (len (spans_list ), 1 )
481+
482+ @mock .patch ("mysql.connector.connect" )
483+ def test_semconv_stable (self , mock_connect ):
484+ """database,http opt-in emits only stable attributes."""
485+ with use_semconv_opt_in ("database,http" ):
486+ mock_connect .return_value = make_mysql_connection_mock ()
487+ MySQLInstrumentor ().instrument ()
488+
489+ connect_and_execute_query ()
490+
491+ spans_list = self .memory_exporter .get_finished_spans ()
492+ self .assertEqual (len (spans_list ), 1 )
493+ span = spans_list [0 ]
494+
495+ self .assertEqual (span .attributes [DB_SYSTEM_NAME ], "mysql" )
496+ self .assertEqual (span .attributes [DB_NAMESPACE ], "test" )
497+ self .assertEqual (
498+ span .attributes [DB_QUERY_TEXT ], "SELECT * FROM test"
499+ )
500+ self .assertEqual (span .attributes [SERVER_ADDRESS ], "localhost" )
501+ self .assertEqual (span .attributes [SERVER_PORT ], 3306 )
502+ self .assertNotIn (DB_SYSTEM , span .attributes )
503+ self .assertNotIn (DB_NAME , span .attributes )
504+ self .assertNotIn (DB_STATEMENT , span .attributes )
505+ self .assertNotIn (DB_USER , span .attributes )
506+ self .assertNotIn (NET_PEER_NAME , span .attributes )
507+ self .assertNotIn (NET_PEER_PORT , span .attributes )
508+
509+ @mock .patch ("mysql.connector.connect" )
510+ def test_semconv_dup (self , mock_connect ):
511+ """database/dup,http/dup opt-in emits both legacy and stable attributes."""
512+ with use_semconv_opt_in ("database/dup,http/dup" ):
513+ mock_connect .return_value = make_mysql_connection_mock ()
514+ MySQLInstrumentor ().instrument ()
515+
516+ connect_and_execute_query ()
517+
518+ spans_list = self .memory_exporter .get_finished_spans ()
519+ self .assertEqual (len (spans_list ), 1 )
520+ span = spans_list [0 ]
521+
522+ self .assertEqual (span .attributes [DB_SYSTEM ], "mysql" )
523+ self .assertEqual (span .attributes [DB_SYSTEM_NAME ], "mysql" )
524+ self .assertEqual (span .attributes [DB_NAME ], "test" )
525+ self .assertEqual (span .attributes [DB_NAMESPACE ], "test" )
526+ self .assertEqual (
527+ span .attributes [DB_STATEMENT ], "SELECT * FROM test"
528+ )
529+ self .assertEqual (
530+ span .attributes [DB_QUERY_TEXT ], "SELECT * FROM test"
531+ )
532+ self .assertEqual (span .attributes [DB_USER ], "testuser" )
533+ self .assertEqual (span .attributes [NET_PEER_NAME ], "localhost" )
534+ self .assertEqual (span .attributes [NET_PEER_PORT ], 3306 )
535+ self .assertEqual (span .attributes [SERVER_ADDRESS ], "localhost" )
536+ self .assertEqual (span .attributes [SERVER_PORT ], 3306 )
0 commit comments