Skip to content

Commit 3aa48b3

Browse files
Add sqlcommenter docs/example
1 parent 64de448 commit 3aa48b3

File tree

5 files changed

+253
-0
lines changed

5 files changed

+253
-0
lines changed
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
sqlcommenter
2+
============
3+
4+
This is an example of how to use OpenTelemetry Python instrumention with
5+
sqlcommenter to enrich database query statements with contextual information.
6+
For more information on sqlcommenter concepts, see:
7+
8+
* `Semantic Conventions - Database Spans <https://github.com/open-telemetry/semantic-conventions/blob/main/docs/database/database-spans.md#sql-commenter>`_
9+
* `sqlcommenter <https://google.github.io/sqlcommenter/>`_
10+
11+
The source files of this example are available `here <https://github.com/open-telemetry/opentelemetry-python/tree/main/docs/examples/sqlcommenter/>`_.
12+
This example uses Docker to manage a database server and OpenTelemetry collector.
13+
14+
Run MySQL server
15+
----------------
16+
17+
A running MySQL server with general logs enabled will store query statements with context resulting from the sqlcommenter feature enabled in this example.
18+
19+
.. code-block:: sh
20+
21+
cd books_database
22+
docker build -t books-db .
23+
docker run -d --name books-db -p 3306:3306 books-db
24+
cd ..
25+
26+
Check that the run worked and the general log is available:
27+
28+
.. code-block:: sh
29+
30+
docker exec -it books-db tail -f /var/log/general.log
31+
32+
Run OpenTelemetry Collector
33+
---------------------------
34+
35+
Running the OpenTelemetry collector will show the MySQL instrumentor's
36+
comment-in-span-attribute feature that the example has also been enabled.
37+
38+
.. code-block:: sh
39+
40+
docker run \
41+
-p 4317:4317 \
42+
-v $(pwd)/collector-config.yaml:/etc/otel/config.yaml \
43+
otel/opentelemetry-collector-contrib:latest
44+
45+
Run the sqlcommenter example
46+
----------------------------
47+
48+
Set up and activate a Python virtual environment. Install these
49+
dependencies of the sqlcommenter example:
50+
51+
.. code-block:: sh
52+
53+
pip install opentelemetry-sdk \
54+
opentelemetry-exporter-otlp-proto-grpc \
55+
opentelemetry-instrumentation-mysql
56+
pip install mysql-connector-python
57+
58+
Then, run this script, which instruments all mysql-connector calls with
59+
two sqlcommenter features opted in. For each ``SELECT`` call, a query is
60+
made with a sqlcomment appended and one OTel span with ``db.statement``
61+
attribute is also generated with sqlcomment.
62+
63+
.. code-block:: sh
64+
65+
python instrumented_query.py
66+
67+
68+
References
69+
----------
70+
71+
* `OpenTelemetry Project <https://opentelemetry.io/>`_
72+
* `OpenTelemetry Collector <https://github.com/open-telemetry/opentelemetry-collector>`_
73+
* `OpenTelemetry MySQL instrumentation <https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/instrumentation/opentelemetry-instrumentation-mysql>`_
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
FROM mysql:8.0
2+
3+
ENV MYSQL_ROOT_PASSWORD=root
4+
ENV MYSQL_DATABASE=books
5+
ENV MYSQL_USER=books
6+
ENV MYSQL_PASSWORD=books123
7+
8+
ADD books.sql /docker-entrypoint-initdb.d/
9+
10+
# Prepare general logs
11+
RUN mkdir -p /var/log && \
12+
touch /var/log/general.log && \
13+
chown mysql:mysql /var/log/general.log
14+
15+
EXPOSE 3306
16+
17+
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
18+
CMD mysqladmin ping -p${MYSQL_ROOT_PASSWORD} || exit 1
19+
20+
# Start MySQL with general logging enabled and compatible authentication
21+
CMD ["mysqld", "--general-log=1", "--general-log-file=/var/log/general.log", "--default-authentication-plugin=mysql_native_password"]
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
-- MySQL dump for Books Database
2+
-- Database: books_db
3+
-- Generated on: 2025-08-29
4+
5+
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
6+
START TRANSACTION;
7+
SET time_zone = "+00:00";
8+
9+
-- Database: `books`
10+
CREATE DATABASE IF NOT EXISTS `books` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
11+
USE `books`;
12+
13+
-- --------------------------------------------------------
14+
15+
-- Table structure for table `authors`
16+
17+
DROP TABLE IF EXISTS `authors`;
18+
CREATE TABLE `authors` (
19+
`id` int(11) NOT NULL AUTO_INCREMENT,
20+
`name` varchar(255) NOT NULL,
21+
`home_town` varchar(255) DEFAULT NULL,
22+
`birthdate` date DEFAULT NULL,
23+
PRIMARY KEY (`id`)
24+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
25+
26+
-- Dumping data for table `authors`
27+
28+
INSERT INTO `authors` (`id`, `name`, `home_town`, `birthdate`) VALUES
29+
(1, 'Frank Herbert', 'Tacoma, Washington', '1920-10-08'),
30+
(2, 'Isaac Asimov', 'Petrovichi, Russia', '1920-01-02'),
31+
(3, 'Terry Pratchett', 'Beaconsfield, England', '1948-04-28');
32+
33+
-- --------------------------------------------------------
34+
35+
-- Table structure for table `books`
36+
37+
DROP TABLE IF EXISTS `books`;
38+
CREATE TABLE `books` (
39+
`id` int(11) NOT NULL AUTO_INCREMENT,
40+
`title` varchar(255) NOT NULL,
41+
`author_id` int(11) NOT NULL,
42+
`year_published` int(4) DEFAULT NULL,
43+
`genre` varchar(100) DEFAULT NULL,
44+
PRIMARY KEY (`id`),
45+
KEY `fk_author` (`author_id`),
46+
CONSTRAINT `fk_author` FOREIGN KEY (`author_id`) REFERENCES `authors` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
47+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
48+
49+
-- Dumping data for table `books`
50+
51+
INSERT INTO `books` (`id`, `title`, `author_id`, `year_published`, `genre`) VALUES
52+
(1, 'Dune', 1, 1965, 'Science Fiction'),
53+
(2, 'Foundation', 2, 1951, 'Science Fiction'),
54+
(3, 'The Colour of Magic', 3, 1983, 'Fantasy Comedy');
55+
56+
-- --------------------------------------------------------
57+
58+
-- Additional books to show the many-to-one relationship
59+
60+
INSERT INTO `books` (`id`, `title`, `author_id`, `year_published`, `genre`) VALUES
61+
(4, 'Dune Messiah', 1, 1969, 'Science Fiction'),
62+
(5, 'I, Robot', 2, 1950, 'Science Fiction'),
63+
(6, 'Good Omens', 3, 1990, 'Fantasy Comedy');
64+
65+
-- --------------------------------------------------------
66+
67+
-- Auto increment values
68+
69+
ALTER TABLE `authors` AUTO_INCREMENT = 4;
70+
ALTER TABLE `books` AUTO_INCREMENT = 7;
71+
72+
COMMIT;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
receivers:
2+
otlp:
3+
protocols:
4+
grpc:
5+
endpoint: 0.0.0.0:4317
6+
7+
exporters:
8+
debug:
9+
verbosity: detailed
10+
11+
processors:
12+
batch:
13+
14+
service:
15+
pipelines:
16+
traces:
17+
receivers: [otlp]
18+
processors: [batch]
19+
exporters: [debug]
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# Copyright The OpenTelemetry Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from mysql.connector import connect
16+
17+
from opentelemetry import trace
18+
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
19+
from opentelemetry.instrumentation.mysql import MySQLInstrumentor
20+
from opentelemetry.sdk.resources import Resource
21+
from opentelemetry.sdk.trace import TracerProvider
22+
from opentelemetry.sdk.trace.export import BatchSpanProcessor
23+
24+
25+
resource = Resource.create(
26+
attributes={
27+
"service.name": "sqlcommenter-example",
28+
}
29+
)
30+
trace.set_tracer_provider(
31+
TracerProvider(
32+
resource=resource
33+
)
34+
)
35+
span_processor = BatchSpanProcessor(
36+
OTLPSpanExporter(
37+
endpoint="http://localhost:4317"
38+
)
39+
)
40+
trace.get_tracer_provider().add_span_processor(span_processor)
41+
42+
# Instrument MySQL queries with sqlcommenter enabled
43+
# and comment-in-span-attribute enabled
44+
MySQLInstrumentor().instrument(
45+
enable_commenter=True,
46+
enable_attribute_commenter=True,
47+
)
48+
49+
cnx = connect(
50+
host="127.0.0.1",
51+
port=3306,
52+
user="books",
53+
password="books123",
54+
database="books",
55+
)
56+
57+
cursor = cnx.cursor()
58+
statement = "SELECT * FROM authors WHERE id = %s"
59+
60+
# Each SELECT query generates one mysql log with sqlcomment
61+
# and one OTel span with `db.statement` attribute that also
62+
# includes sqlcomment.
63+
for cid in range(1, 3):
64+
cursor.execute(statement, (cid,))
65+
rows = cursor.fetchall()
66+
print(f"Found author: {rows[0]}")
67+
68+
print("Done.")

0 commit comments

Comments
 (0)