Skip to content
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

SQLAlchemy: db.statement inclusion of sqlcomment as opt-in #3112

Open
wants to merge 18 commits into
base: main
Choose a base branch
from

Conversation

tammy-baylis-swi
Copy link
Contributor

@tammy-baylis-swi tammy-baylis-swi commented Dec 16, 2024

Description

Supports new, optional kwarg enable_attribute_commenter at SQLAlchemy instrumentation to opt into db.statement span attribute inclusion of sqlcomment.

Partially addresses #3107

Type of change

Breaking because db.statement span attribute inclusion of sqlcomment currently always happens if sqlcommenter enabled. It'll be opt-in with this update, so might break for those users relying on the feature introduced in 0.50b0.

  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

  • tox -e py312-test-instrumentation-sqlalchemy-0
  • tox -e py312-test-instrumentation-sqlalchemy-1
  • tox -e py312-test-instrumentation-sqlalchemy-2
  • Instrumentation of a test app to check span attributes and mysql server logs when enable_attribute_commenter=True vs unset

Does This PR Require a Core Repo Change?

  • No.

Checklist:

  • Followed the style guidelines of this project
  • Changelogs have been updated
  • Unit tests have been added
  • Documentation has been updated

@tammy-baylis-swi tammy-baylis-swi marked this pull request as ready for review December 17, 2024 20:20
@tammy-baylis-swi tammy-baylis-swi requested a review from a team as a code owner December 17, 2024 20:20
@tammy-baylis-swi
Copy link
Contributor Author

cc'ing @alexmojaki , feel free to comment/review!

self.enable_commenter
and not self.enable_attribute_commenter
):
statement = _add_sql_comment(statement, **commenter_data)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need the _add_sql_comment after the set_attribute statement?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shalevr ! At this condition, user has enabled sqlcommenting but has not opted into "enable attribute commenter". So db.statement get written first without sqlcomment, then sqlcomment is added to the query statement before execution.

and not self.enable_attribute_commenter
):
statement = _add_sql_comment(statement, **commenter_data)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line 267 and this line look the same both have self.enable_commenter=True, but on line 267, self.enable_attribute_commenter=True, while in this condition, self.enable_attribute_commenter=False. So, what's the difference? Can we call _add_sql_comment once to make it clearer

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll see how I can rearrange and add comments to make it more clear!

Currently L247 checks self.enable_commenter=True and L267 checks self.enable_attribute_commenter=True. If so, we _add_sql_comment first so that both db.statement attribute and executed query statement include the sqlcomment.

This next part is unclear to me too now 😅 If at L247 self.enable_commenter=False, then db.statement gets set first without sqlcomment. Then at L276 we check again?! Not sure how the tests are passing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shalevr How does it look now? This time it's an if-(if-else)-else with comments.

@tammy-baylis-swi tammy-baylis-swi requested a review from a team December 19, 2024 19:34

def _set_db_client_span_attributes(self, span, statement, attrs) -> None:
"""Uses statement and attrs to set attributes of provided Otel span"""
span.set_attribute(SpanAttributes.DB_STATEMENT, statement)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prob isn't related, but shouldn't these attributes be provided at span creation? For sampling decisions.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If so, maybe we can pass them at span creation and convert this method to a staticmethod that just update the statement with the statement with commenter_data.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If so, maybe we can pass them at span creation and convert this method to a staticmethod that just update the statement with the statement with commenter_data.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The calls to set_attribute in this instrumentor generally have been set to only happen if span.is_recording(), which for this (new) helper is at L272. This condition was introduced in open-telemetry/opentelemetry-python#1057 to improve performance, so I think that part should be kept in. Then regarding staticmethod, I'm not sure if it'll be possible but maybe I miss something. Thoughts? 🙂

}

if self.commenter_options.get("opentelemetry_values", True):
commenter_data.update(**_get_opentelemetry_values())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related to this comment it seems strange to have trace context related information in a span attribute. I am okay with sqlcommenting as part of the attribute but maybe we can omit the OT values?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capturing Otel context in db.statement is a convenience for checking that sqlcommenter is enabled with the current config, and checking that the expected trace context was injected into the query statement sent from db client app to to the db server. The latter is an instrumentation checkup; duplicate traceparent can be sqlcommented if both SQLAlchemy (ORM) and db driver (e.g. pymysql/psycopg2) are enabled unintentionally and this could mess with the client-server correlation.

It's not a requirement since all can both be checked in the mysql/postgresql server general logs. But diagnosing issues is quicker with db.statement inclusion of full sqlcomment, e.g. looking at span attributes in a local otel-collector exporting to console versus accessing a mysql server and opening its logs. Or e.g. looking at spans exported to a platform versus getting creds and accessing a cloud-hosted db server.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants