Skip to content

feat(instrumentation-pg): update to stable semantic conventions #2881

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

42 changes: 42 additions & 0 deletions plugins/node/opentelemetry-instrumentation-pg/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,48 @@ PostgreSQL instrumentation has few options available to choose from. You can set
| `requireParentSpan` | `boolean` | If true, requires a parent span to create new spans (default false) |
| `addSqlCommenterCommentToQueries` | `boolean` | If true, adds [sqlcommenter](https://github.com/open-telemetry/opentelemetry-sqlcommenter) specification compliant comment to queries with tracing context (default false). _NOTE: A comment will not be added to queries that already contain `--` or `/* ... */` in them, even if these are not actually part of comments_ |

## Semantic Conventions

Prior to version `0.55.0`, this instrumentation created spans and metrics targeting an experimental semantic convention Version 1.27.0.

Database semantic conventions (semconv) were stabilized in v1.34.0, and a [migration process](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/non-normative/db-migration.md) was defined.
`opentelemetry-instrumentation-pg` versions 0.55.0 and later include support for migrating to stable Database semantic conventions, as described below.
The intent is to provide an approximate 6 month time window for users of this instrumentation to migrate to the new Database semconv, after which a new minor version will use the new semconv by default and drop support for the old semconv.

To select which semconv version(s) is emitted from this instrumentation, use the `OTEL_SEMCONV_STABILITY_OPT_IN` environment variable.

- `database`: emit the new (stable) v1.34.0+ semantics
- `database/dup`: emit **both** the old v1.27.0 and the new (stable) v1.34.0+ semantics
- By default, if `OTEL_SEMCONV_STABILITY_OPT_IN` includes neither of the above tokens, the old v1.27.0 semconv is used.

### Attributes collected

| v1.27.0 semconv | v1.34.0 semconv | Short Description |
| ----------------------- | ----------------------------------------------- | ------------------------------------------------------------------------------------------ |
| `db.connection_string` | Removed | String used to connect to the database |
| `db.user` | Removed | User used to connect to the database |
| `db.name` | Removed, integrated into the new `db.namespace` | The name of the database. |
| (not included) | `db.namespace` | The name of the database, fully qualified within the server address and port. |
| `db.statement` | `db.query.text` | The database query being executed. |
| `db.system` | `db.system.name` | The database management system (DBMS) product as identified by the client instrumentation. |
| `net.peer.port` | `server.port` | Remote port number. |
| `net.peer.name` | `server.address` | Remote hostname or similar. |

Metrics Exported:

- [`db.client.operation.duration`](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/database/database-metrics.md#metric-dbclientoperationduration)

### Upgrading Semantic Conventions

When upgrading to the new semantic conventions, it is recommended to do so in the following order:

1. Upgrade `@opentelemetry/opentelemetry-instrumentation-pg` to the latest version
2. Set `OTEL_SEMCONV_STABILITY_OPT_IN=database/dup` to emit both old and new semantic conventions
3. Modify alerts, dashboards, metrics, and other processes to expect the new semantic conventions
4. Set `OTEL_SEMCONV_STABILITY_OPT_IN=database` to emit only the new semantic conventions

This will cause both the old and new semantic conventions to be emitted during the transition period.

## Useful links

- For more information on OpenTelemetry, visit: <https://opentelemetry.io/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
"dependencies": {
"@opentelemetry/core": "^2.0.0",
"@opentelemetry/instrumentation": "^0.202.0",
"@opentelemetry/semantic-conventions": "^1.27.0",
"@opentelemetry/semantic-conventions": "^1.34.0",
"@opentelemetry/sql-common": "^0.41.0",
"@types/pg": "8.15.1",
"@types/pg-pool": "2.0.6"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
InstrumentationNodeModuleDefinition,
safeExecuteInTheMiddle,
InstrumentationNodeModuleFile,
SemconvStability,
semconvStabilityFromStr,
} from '@opentelemetry/instrumentation';
import {
context,
Expand Down Expand Up @@ -54,18 +56,19 @@
hrTimeToMilliseconds,
} from '@opentelemetry/core';
import {
DBSYSTEMVALUES_POSTGRESQL,
SEMATTRS_DB_SYSTEM,
ATTR_ERROR_TYPE,
ATTR_SERVER_PORT,
ATTR_SERVER_ADDRESS,
ATTR_DB_SYSTEM_NAME,
} from '@opentelemetry/semantic-conventions';
import {
METRIC_DB_CLIENT_CONNECTION_COUNT,
METRIC_DB_CLIENT_CONNECTION_PENDING_REQUESTS,
METRIC_DB_CLIENT_OPERATION_DURATION,
ATTR_DB_NAMESPACE,
ATTR_DB_OPERATION_NAME,
ATTR_DB_SYSTEM,
DB_SYSTEM_VALUE_POSTGRESQL,
} from './semconv';

function extractModuleExports(module: any) {
Expand All @@ -88,9 +91,14 @@
idle: 0,
pending: 0,
};
private _semconvStability: SemconvStability;

constructor(config: PgInstrumentationConfig = {}) {
super(PACKAGE_NAME, PACKAGE_VERSION, config);
this._semconvStability = semconvStabilityFromStr(
'database',
process.env.OTEL_SEMCONV_STABILITY_OPT_IN
);
}

override _updateMetricInstruments() {
Expand Down Expand Up @@ -247,7 +255,10 @@

const span = plugin.tracer.startSpan(SpanNames.CONNECT, {
kind: SpanKind.CLIENT,
attributes: utils.getSemanticAttributesFromConnection(this),
attributes: utils.getSemanticAttributesFromConnection(
this,
plugin._semconvStability
),
});

if (callback) {
Expand All @@ -273,13 +284,18 @@
private recordOperationDuration(attributes: Attributes, startTime: HrTime) {
const metricsAttributes: Attributes = {};
const keysToCopy = [
SEMATTRS_DB_SYSTEM,
ATTR_DB_NAMESPACE,
ATTR_ERROR_TYPE,
ATTR_SERVER_PORT,
ATTR_SERVER_ADDRESS,
ATTR_DB_OPERATION_NAME,
];
if (this._semconvStability & SemconvStability.OLD) {
keysToCopy.push(ATTR_DB_SYSTEM);
}
if (this._semconvStability & SemconvStability.STABLE) {
keysToCopy.push(ATTR_DB_SYSTEM_NAME);

Check warning on line 297 in plugins/node/opentelemetry-instrumentation-pg/src/instrumentation.ts

View check run for this annotation

Codecov / codecov/patch

plugins/node/opentelemetry-instrumentation-pg/src/instrumentation.ts#L297

Added line #L297 was not covered by tests
}

keysToCopy.forEach(key => {
if (key in attributes) {
Expand Down Expand Up @@ -327,7 +343,7 @@
: undefined;

const attributes: Attributes = {
[SEMATTRS_DB_SYSTEM]: DBSYSTEMVALUES_POSTGRESQL,
[ATTR_DB_SYSTEM]: DB_SYSTEM_VALUE_POSTGRESQL,
[ATTR_DB_NAMESPACE]: this.database,
[ATTR_SERVER_PORT]: this.connectionParameters.port,
[ATTR_SERVER_ADDRESS]: this.connectionParameters.host,
Expand All @@ -348,6 +364,7 @@
this,
plugin.tracer,
instrumentationConfig,
plugin._semconvStability,
queryConfig
);

Expand Down Expand Up @@ -548,7 +565,10 @@
// setup span
const span = plugin.tracer.startSpan(SpanNames.POOL_CONNECT, {
kind: SpanKind.CLIENT,
attributes: utils.getSemanticAttributesFromPool(this.options),
attributes: utils.getSemanticAttributesFromPool(
this.options,
plugin._semconvStability
),
});

plugin._setPoolConnectEventListeners(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export type PostgresCallback = (err: Error, res: object) => unknown;
export interface PgParsedConnectionParams {
database?: string;
host?: string;
namespace?: string;
port?: number;
user?: string;
}
Expand All @@ -47,17 +48,18 @@ export type PgPoolCallback = (
) => void;

export interface PgPoolOptionsParams {
allowExitOnIdle: boolean;
connectionString?: string; // connection string if provided directly
database: string;
host: string;
port: number;
user: string;
idleTimeoutMillis: number; // the minimum amount of time that an object may sit idle in the pool before it is eligible for eviction due to idle time
maxClient: number; // maximum size of the pool
connectionString?: string; // connection string if provided directly
max: number;
maxUses: number;
allowExitOnIdle: boolean;
maxClient: number; // maximum size of the pool
maxLifetimeSeconds: number;
maxUses: number;
namespace: string;
port: number;
user: string;
}

export const EVENT_LISTENERS_SET = Symbol(
Expand Down
51 changes: 51 additions & 0 deletions plugins/node/opentelemetry-instrumentation-pg/src/semconv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,54 @@ export const METRIC_DB_CLIENT_CONNECTION_PENDING_REQUESTS =
*/
export const METRIC_DB_CLIENT_OPERATION_DURATION =
'db.client.operation.duration';

/**
* An identifier for the database management system (DBMS) product being used.
*
*/
export const ATTR_DB_SYSTEM = 'db.system';

/**
* An identifier for the database management system (DBMS) product being used. See below for a list of well-known identifiers.
*
*/
export const DB_SYSTEM_VALUE_POSTGRESQL = 'postgresql';

/**
* If no [tech-specific attribute](#call-level-attributes-for-specific-technologies) is defined, this attribute is used to report the name of the database being accessed. For commands that switch the database, this should be set to the target database (even if the command fails).
*
* Note: In some SQL databases, the database name to be used is called &#34;schema name&#34;.
*
*/
export const ATTR_DB_NAME = 'db.name';

/**
* The connection string used to connect to the database. It is recommended to remove embedded credentials.
*
*/
export const ATTR_DB_CONNECTION_STRING = 'db.connection_string';

/**
* Username for accessing the database.
*
*/
export const ATTR_DB_USER = 'db.user';

/**
* Remote port number.
*
*/
export const ATTR_NET_PEER_PORT = 'net.peer.port';
/**
* Remote hostname or similar.
*
*/
export const ATTR_NET_PEER_NAME = 'net.peer.name';

/**
* The database statement being executed.
*
* Note: The value may be sanitized to exclude sensitive information.
*
*/
export const ATTR_DB_STATEMENT = 'db.statement';
Loading