-
Notifications
You must be signed in to change notification settings - Fork 40
feat: add identity attributes to OTLP logs #308
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
Merged
+245
−27
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
fb011a0
Added log filter with identity attributes
LucasAlvesSoares 17120bb
Linting
LucasAlvesSoares 41cb08c
Linting
LucasAlvesSoares bb723aa
version bump
LucasAlvesSoares 6707b1e
Merge branch 'main' into logging-attributes
LucasAlvesSoares 8c266e7
User guide
LucasAlvesSoares 48f87ea
Module indicators
LucasAlvesSoares d67b91d
Module indicators
LucasAlvesSoares 6bdee89
Module indicators
LucasAlvesSoares 7658011
User guide
LucasAlvesSoares File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| from sap_cloud_sdk.core.telemetry.log_filters.identity import IdentityLogFilter | ||
|
|
||
| __all__ = ["IdentityLogFilter"] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| """Log filter that stamps identity attributes (tenant ID, user ID) onto every log record.""" | ||
|
|
||
| import logging | ||
|
|
||
| from sap_cloud_sdk.core.telemetry.constants import ATTR_SAP_TENANT_ID, ATTR_USER_ID | ||
|
|
||
|
|
||
| def _resolve_log_attributes() -> dict: | ||
| try: | ||
| from sap_cloud_sdk.core.runtime_context import ( | ||
| get_context, | ||
| GLOBAL_TENANT_ID, | ||
| USER_ID, | ||
| ) | ||
| from sap_cloud_sdk.ias import get_auth_context | ||
|
|
||
| ctx = get_context() | ||
| claims = get_auth_context() | ||
| candidates = { | ||
| ATTR_SAP_TENANT_ID: ctx.get(GLOBAL_TENANT_ID) | ||
| or (claims and claims.sap_gtid), | ||
| ATTR_USER_ID: ctx.get(USER_ID) or (claims and claims.user_uuid), | ||
| } | ||
| return {k: v for k, v in candidates.items() if v} | ||
| except Exception: | ||
| return {} | ||
|
|
||
|
|
||
| class IdentityLogFilter(logging.Filter): | ||
| """Stamps ``sap.tenancy.tenant_id`` and ``user.id`` onto every log record. | ||
|
|
||
| Reads from the SDK runtime context first (populated by ``bootstrap()``), | ||
| then falls back to the IAS auth context set by the Starlette middleware. | ||
| Attributes are omitted when no identity is available (e.g. outside a request). | ||
| """ | ||
|
|
||
| def filter(self, record: logging.LogRecord) -> bool: | ||
| for attr, value in _resolve_log_attributes().items(): | ||
| setattr(record, attr, value) | ||
| return True |
15 changes: 15 additions & 0 deletions
15
src/sap_cloud_sdk/core/telemetry/span_processors/__init__.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| from sap_cloud_sdk.core.telemetry.span_processors.baggage_span_processor import ( | ||
| BaggageSpanProcessor, | ||
| ) | ||
| from sap_cloud_sdk.core.telemetry.span_processors.propagated_attributes_processor import ( | ||
| PropagatedAttributesSpanProcessor, | ||
| ) | ||
| from sap_cloud_sdk.core.telemetry.span_processors.runtime_context_processor import ( | ||
| RuntimeContextSpanProcessor, | ||
| ) | ||
|
|
||
| __all__ = [ | ||
| "BaggageSpanProcessor", | ||
| "PropagatedAttributesSpanProcessor", | ||
| "RuntimeContextSpanProcessor", | ||
| ] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| """Tests for log_filters.identity.""" | ||
|
|
||
| import logging | ||
| from unittest.mock import patch | ||
|
|
||
| import pytest | ||
|
|
||
| from sap_cloud_sdk.core.telemetry.log_filters.identity import ( | ||
| IdentityLogFilter, | ||
| _resolve_log_attributes, | ||
| ) | ||
| from sap_cloud_sdk.core.telemetry.constants import ATTR_SAP_TENANT_ID, ATTR_USER_ID | ||
|
|
||
|
|
||
| def _make_record() -> logging.LogRecord: | ||
| return logging.LogRecord("test", logging.INFO, "", 0, "msg", (), None) | ||
|
|
||
|
|
||
| class TestResolveLogAttributes: | ||
| def test_returns_tenant_and_user_from_runtime_context(self): | ||
| from sap_cloud_sdk.core.runtime_context.providers._ias import GLOBAL_TENANT_ID, USER_ID | ||
| from sap_cloud_sdk.core.runtime_context._context import RuntimeContext, sdk_context | ||
|
|
||
| ctx = RuntimeContext({GLOBAL_TENANT_ID: "t-1", USER_ID: "u-1"}) | ||
| with sdk_context(ctx): | ||
| attrs = _resolve_log_attributes() | ||
|
|
||
| assert attrs == {ATTR_SAP_TENANT_ID: "t-1", ATTR_USER_ID: "u-1"} | ||
|
|
||
| def test_falls_back_to_auth_context(self): | ||
| from sap_cloud_sdk.core.runtime_context._context import RuntimeContext, sdk_context | ||
| from sap_cloud_sdk.ias._context import _auth_context_var | ||
| from sap_cloud_sdk.ias._token import IASClaims | ||
|
|
||
| claims = IASClaims(sap_gtid="gtid-1", user_uuid="uuid-1") | ||
| token = _auth_context_var.set(claims) | ||
| try: | ||
| with sdk_context(RuntimeContext()): | ||
| attrs = _resolve_log_attributes() | ||
| finally: | ||
| _auth_context_var.reset(token) | ||
|
|
||
| assert attrs == {ATTR_SAP_TENANT_ID: "gtid-1", ATTR_USER_ID: "uuid-1"} | ||
|
|
||
| def test_returns_empty_when_nothing_set(self): | ||
| from sap_cloud_sdk.core.runtime_context._context import RuntimeContext, sdk_context | ||
|
|
||
| with sdk_context(RuntimeContext()): | ||
| assert _resolve_log_attributes() == {} | ||
|
|
||
| def test_returns_empty_on_exception(self): | ||
| with patch("sap_cloud_sdk.core.runtime_context.get_context", side_effect=Exception("boom")): | ||
| assert _resolve_log_attributes() == {} | ||
|
|
||
|
|
||
| class TestIdentityLogFilter: | ||
| def test_stamps_all_resolved_attributes(self): | ||
| from sap_cloud_sdk.core.runtime_context.providers._ias import GLOBAL_TENANT_ID, USER_ID | ||
| from sap_cloud_sdk.core.runtime_context._context import RuntimeContext, sdk_context | ||
|
|
||
| ctx = RuntimeContext({GLOBAL_TENANT_ID: "t-1", USER_ID: "u-1"}) | ||
| record = _make_record() | ||
| filt = IdentityLogFilter() | ||
|
|
||
| with sdk_context(ctx): | ||
| result = filt.filter(record) | ||
|
|
||
| assert result is True | ||
| assert getattr(record, ATTR_SAP_TENANT_ID) == "t-1" | ||
| assert getattr(record, ATTR_USER_ID) == "u-1" | ||
|
|
||
| def test_skips_attributes_when_nothing_set(self): | ||
| from sap_cloud_sdk.core.runtime_context._context import RuntimeContext, sdk_context | ||
|
|
||
| record = _make_record() | ||
| filt = IdentityLogFilter() | ||
|
|
||
| with sdk_context(RuntimeContext()): | ||
| result = filt.filter(record) | ||
|
|
||
| assert result is True | ||
| assert not hasattr(record, ATTR_SAP_TENANT_ID) | ||
| assert not hasattr(record, ATTR_USER_ID) | ||
|
|
||
| def test_always_returns_true(self): | ||
| record = _make_record() | ||
| filt = IdentityLogFilter() | ||
| with patch("sap_cloud_sdk.core.telemetry.log_filters.identity._resolve_log_attributes", return_value={}): | ||
| assert filt.filter(record) is True |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.