Skip to content

Commit 3757d85

Browse files
Dev/skruk/fix user plugin (#68)
* feat: Add two-phase commit for query telemetry and configurable event log lookback window - Implement two-phase commit pattern in `_process_span_rows` to prevent silent data loss when trace export fails by only marking queries as processed after successful OTLP flush - Add `plugins.event_log.lookback_hours` configuration option (default: 24) to replace hardcoded 24-hour lookback window in `V_EVENT_LOG` - Add comprehensive test coverage for query hierarchy validation with nested stored procedure chains * feat: Add authentication method attributes to Users plugin - Add `snowflake.user.has_mfa` attribute to indicate multi-factor authentication enrollment status - Add `snowflake.user.has_pat` attribute to indicate programmatic access token configuration - Add `snowflake.user.has_rsa` attribute to indicate RSA public key authentication configuration - Add `snowflake.user.has_workload_identity` attribute to indicate workload identity federation configuration - Update TMP_USERS and TMP_USERS_HELPER table * fix: Update log attribute adjustment to handle None values correctly fix: Update secure_objects_only field to use TRY_TO_BOOLEAN for proper type conversion
1 parent d6a07f7 commit 3757d85

File tree

22 files changed

+220
-15
lines changed

22 files changed

+220
-15
lines changed

docs/SEMANTICS.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -733,7 +733,11 @@ check the `Context Name` column below.
733733
| snowflake.​user.​expires_at | The expiration date of the user account. | 1620213179885000000 | users |
734734
| snowflake.​user.​ext_authn.​duo | Indicates if Duo authentication is enabled for the user. | true | users |
735735
| snowflake.​user.​ext_authn.​uid | The external authentication UID for the user. | ext123 | users |
736+
| snowflake.&#8203;user.&#8203;has_mfa | Indicates if the user is enrolled for multi<br>-factor authentication. | true | users |
736737
| snowflake.&#8203;user.&#8203;has_password | Indicates if the user has a password set. | true | users |
738+
| snowflake.&#8203;user.&#8203;has_pat | Indicates if a programmatic access token has been generated for the user. | true | users |
739+
| snowflake.&#8203;user.&#8203;has_rsa | Indicates if RSA public key authentication is configured for the user. | true | users |
740+
| snowflake.&#8203;user.&#8203;has_workload_identity | Indicates if workload identity federation is configured for the user. | true | users |
737741
| snowflake.&#8203;user.&#8203;id | The unique identifier for the user. | 12345 | users |
738742
| snowflake.&#8203;user.&#8203;is_disabled | Indicates if the user account is disabled. | false | users |
739743
| snowflake.&#8203;user.&#8203;is_from_organization | Indicates if the user was imported from a global organization. | true | users |

src/dtagent/otel/logs.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ def __adjust_log_attribute(key: str, value: Any) -> Any:
172172

173173
# the following conversions through JSON are necessary to ensure certain objects like datetime are properly serialized,
174174
# otherwise OTEL seems to be sending objects cannot be deserialized on the Dynatrace side
175-
o_extra = {k: __adjust_log_attribute(k, v) for k, v in _cleanup_data(extra).items() if v} if extra else {}
175+
o_extra = {k: __adjust_log_attribute(k, v) for k, v in _cleanup_data(extra).items() if v is not None} if extra else {}
176176

177177
# Process timestamps using standard pattern:
178178
# - timestamp in milliseconds (Dynatrace OTLP Logs API deviation from spec)

src/dtagent/plugins/shares.sql/061_v_inbound_shares.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ select
6565
'snowflake.share.shared_from', s.owner_account,
6666
'snowflake.share.shared_to', s.given_to,
6767
'snowflake.share.owner', s.owner,
68-
'snowflake.share.is_secure_objects_only', s.secure_objects_only,
68+
'snowflake.share.is_secure_objects_only', TRY_TO_BOOLEAN(s.secure_objects_only),
6969
'snowflake.share.listing_global_name', s.listing_global_name,
7070
'snowflake.error.message', ins.DETAILS:"ERROR_MESSAGE"
7171
) as ATTRIBUTES,

src/dtagent/plugins/shares.sql/061_v_outbound_shares.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ select
4848
'snowflake.share.shared_from', s.owner_account,
4949
'snowflake.share.shared_to', s.given_to,
5050
'snowflake.share.owner', s.owner,
51-
'snowflake.share.is_secure_objects_only', s.secure_objects_only,
51+
'snowflake.share.is_secure_objects_only', TRY_TO_BOOLEAN(s.secure_objects_only),
5252
'snowflake.share.listing_global_name', s.listing_global_name
5353
) as ATTRIBUTES,
5454
OBJECT_CONSTRUCT(

src/dtagent/plugins/shares.sql/061_v_share_events.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ select
4242
'snowflake.share.shared_from', s.owner_account,
4343
'snowflake.share.shared_to', s.given_to,
4444
'snowflake.share.owner', s.owner,
45-
'snowflake.share.is_secure_objects_only', s.secure_objects_only,
45+
'snowflake.share.is_secure_objects_only', TRY_TO_BOOLEAN(s.secure_objects_only),
4646
'snowflake.share.listing_global_name', s.listing_global_name
4747
) as ATTRIBUTES,
4848

src/dtagent/plugins/users.config/instruments-def.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,31 @@ attributes:
7777
__context_names:
7878
- users
7979
__description: The external authentication UID for the user.
80+
snowflake.user.has_mfa:
81+
__example: "true"
82+
__context_names:
83+
- users
84+
__description: Indicates if the user is enrolled for multi-factor authentication.
8085
snowflake.user.has_password:
8186
__example: "true"
8287
__context_names:
8388
- users
8489
__description: Indicates if the user has a password set.
90+
snowflake.user.has_pat:
91+
__example: "true"
92+
__context_names:
93+
- users
94+
__description: Indicates if a programmatic access token has been generated for the user.
95+
snowflake.user.has_rsa:
96+
__example: "true"
97+
__context_names:
98+
- users
99+
__description: Indicates if RSA public key authentication is configured for the user.
100+
snowflake.user.has_workload_identity:
101+
__example: "true"
102+
__context_names:
103+
- users
104+
__description: Indicates if workload identity federation is configured for the user.
85105
snowflake.user.id:
86106
__example: "12345"
87107
__context_names:

src/dtagent/plugins/users.sql/051_p_get_users.sql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ create or replace transient table DTAGENT_DB.APP.TMP_USERS (
3434
ext_authn_duo boolean, ext_authn_uid text, has_mfa boolean, bypass_mfa_until timestamp_ltz,
3535
last_success_login timestamp_ltz, expires_at timestamp_ltz, locked_until_time timestamp_ltz,
3636
has_rsa_public_key boolean, password_last_set_time timestamp_ltz,
37+
has_pat boolean, has_workload_identity boolean,
3738
owner text, default_secondary_role text, type text,
3839
database_name text, database_id number, schema_name text, schema_id number,
3940
is_from_organization_user boolean)
@@ -50,6 +51,7 @@ create or replace transient table DTAGENT_DB.APP.TMP_USERS_HELPER (
5051
ext_authn_duo boolean, ext_authn_uid text, has_mfa boolean, bypass_mfa_until timestamp_ltz,
5152
last_success_login timestamp_ltz, expires_at timestamp_ltz, locked_until_time timestamp_ltz,
5253
has_rsa_public_key boolean, password_last_set_time timestamp_ltz,
54+
has_pat boolean, has_workload_identity boolean,
5355
owner text, default_secondary_role text, type text,
5456
database_name text, database_id number, schema_name text, schema_id number,
5557
is_from_organization_user boolean)
@@ -78,6 +80,7 @@ DECLARE
7880
ext_authn_duo, ext_authn_uid, has_mfa, bypass_mfa_until,
7981
last_success_login, expires_at, locked_until_time,
8082
has_rsa_public_key, password_last_set_time,
83+
has_pat, has_workload_identity,
8184
owner, default_secondary_role, type,
8285
database_name, database_id, schema_name, schema_id,
8386
is_from_organization_user

src/dtagent/plugins/users.sql/071_v_users_instrumented.sql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ select
5353
'snowflake.user.default.role', u.default_role,
5454
'snowflake.user.ext_authn.duo', u.ext_authn_duo,
5555
'snowflake.user.ext_authn.uid', u.ext_authn_uid,
56+
'snowflake.user.has_rsa', u.has_rsa_public_key,
57+
'snowflake.user.has_mfa', u.has_mfa,
58+
'snowflake.user.has_pat', u.has_pat,
59+
'snowflake.user.has_workload_identity', u.has_workload_identity,
5660
'snowflake.user.owner', u.owner,
5761
'snowflake.user.default.secondary_role', u.default_secondary_role,
5862
'snowflake.user.type', u.type,
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
{"_MESSAGE": "Share details for Monte Carlo", "DIMENSIONS": "{\n \"db.namespace\": \"\",\n \"snowflake.share.name\": \"Monte Carlo\"\n}", "ATTRIBUTES": "{\n \"snowflake.share.is_secure_objects_only\": \"\",\n \"snowflake.share.kind\": \"INBOUND\",\n \"snowflake.share.listing_global_name\": \"\",\n \"snowflake.share.owner\": \"\",\n \"snowflake.share.shared_from\": \"TEST123.TESTACCOUNT\",\n \"snowflake.share.shared_to\": \"\"\n}", "EVENT_TIMESTAMPS": "{\n \"snowflake.share.created_on\": 1633629486209000000\n}"}
2-
{"_MESSAGE": "Share details for ACCOUNT_USAGE", "DIMENSIONS": "{\n \"db.namespace\": \"SNOWFLAKE\",\n \"snowflake.share.name\": \"ACCOUNT_USAGE\"\n}", "ATTRIBUTES": "{\n \"snowflake.share.is_secure_objects_only\": \"\",\n \"snowflake.share.kind\": \"INBOUND\",\n \"snowflake.share.listing_global_name\": \"\",\n \"snowflake.share.owner\": \"\",\n \"snowflake.share.shared_from\": \"SNOWFLAKE\",\n \"snowflake.share.shared_to\": \"\"\n}", "EVENT_TIMESTAMPS": "{\n \"snowflake.share.created_on\": 1568850151405000000\n}"}
1+
{"_MESSAGE": "Share details for Monte Carlo", "DIMENSIONS": "{\n \"db.namespace\": \"\",\n \"snowflake.share.name\": \"Monte Carlo\"\n}", "ATTRIBUTES": "{\n \"snowflake.share.kind\": \"INBOUND\",\n \"snowflake.share.listing_global_name\": \"\",\n \"snowflake.share.owner\": \"\",\n \"snowflake.share.shared_from\": \"TEST123.TESTACCOUNT\",\n \"snowflake.share.shared_to\": \"\"\n}", "EVENT_TIMESTAMPS": "{\n \"snowflake.share.created_on\": 1633629486209000000\n}"}
2+
{"_MESSAGE": "Share details for ACCOUNT_USAGE", "DIMENSIONS": "{\n \"db.namespace\": \"SNOWFLAKE\",\n \"snowflake.share.name\": \"ACCOUNT_USAGE\"\n}", "ATTRIBUTES": "{\n \"snowflake.share.kind\": \"INBOUND\",\n \"snowflake.share.listing_global_name\": \"\",\n \"snowflake.share.owner\": \"\",\n \"snowflake.share.shared_from\": \"SNOWFLAKE\",\n \"snowflake.share.shared_to\": \"\"\n}", "EVENT_TIMESTAMPS": "{\n \"snowflake.share.created_on\": 1568850151405000000\n}"}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
{"_MESSAGE": "Inbound share details for BIET_MONITORING_SHARE", "DIMENSIONS": "{\n \"db.namespace\": \"BI_SHARE_MONITORING_DB\",\n \"snowflake.share.name\": \"BIET_MONITORING_SHARE\"\n}", "ATTRIBUTES": "{\n \"snowflake.share.has_details_reported\": true,\n \"snowflake.share.is_secure_objects_only\": \"\",\n \"snowflake.share.kind\": \"INBOUND\",\n \"snowflake.share.listing_global_name\": \"\",\n \"snowflake.share.owner\": \"\",\n \"snowflake.share.shared_from\": \"TEST123.TESTACCOUNT\",\n \"snowflake.share.shared_to\": \"\"\n}", "EVENT_TIMESTAMPS": "{}"}
2-
{"_MESSAGE": "Inbound share details for BIET_MONITORING_SHARE", "DIMENSIONS": "{\n \"db.namespace\": \"DT_SHARE_MONITORING_DB\",\n \"snowflake.share.name\": \"BIET_MONITORING_SHARE\"\n}", "ATTRIBUTES": "{\n \"snowflake.share.has_details_reported\": true,\n \"snowflake.share.is_secure_objects_only\": \"\",\n \"snowflake.share.kind\": \"INBOUND\",\n \"snowflake.share.listing_global_name\": \"\",\n \"snowflake.share.owner\": \"\",\n \"snowflake.share.shared_from\": \"TEST123.TESTACCOUNT_WA\",\n \"snowflake.share.shared_to\": \"\"\n}", "EVENT_TIMESTAMPS": "{}"}
1+
{"_MESSAGE": "Inbound share details for BIET_MONITORING_SHARE", "DIMENSIONS": "{\n \"db.namespace\": \"BI_SHARE_MONITORING_DB\",\n \"snowflake.share.name\": \"BIET_MONITORING_SHARE\"\n}", "ATTRIBUTES": "{\n \"snowflake.share.has_details_reported\": true,\n \"snowflake.share.kind\": \"INBOUND\",\n \"snowflake.share.listing_global_name\": \"\",\n \"snowflake.share.owner\": \"\",\n \"snowflake.share.shared_from\": \"TEST123.TESTACCOUNT\",\n \"snowflake.share.shared_to\": \"\"\n}", "EVENT_TIMESTAMPS": "{}"}
2+
{"_MESSAGE": "Inbound share details for BIET_MONITORING_SHARE", "DIMENSIONS": "{\n \"db.namespace\": \"DT_SHARE_MONITORING_DB\",\n \"snowflake.share.name\": \"BIET_MONITORING_SHARE\"\n}", "ATTRIBUTES": "{\n \"snowflake.share.has_details_reported\": true,\n \"snowflake.share.kind\": \"INBOUND\",\n \"snowflake.share.listing_global_name\": \"\",\n \"snowflake.share.owner\": \"\",\n \"snowflake.share.shared_from\": \"TEST123.TESTACCOUNT_WA\",\n \"snowflake.share.shared_to\": \"\"\n}", "EVENT_TIMESTAMPS": "{}"}
33
{"_MESSAGE": "Inbound share \"DELETED_DB_SHARE\" has a deleted database - data is no longer accessible", "DIMENSIONS": "{\n \"db.namespace\": \"DELETED_SHARED_DB\",\n \"snowflake.share.name\": \"DELETED_DB_SHARE\"\n}", "ATTRIBUTES": "{\n \"snowflake.share.has_db_deleted\": true,\n \"snowflake.share.has_details_reported\": true,\n \"snowflake.share.kind\": \"INBOUND\",\n \"snowflake.share.shared_from\": \"ABC123.SOURCE_ACCOUNT\"\n}", "EVENT_TIMESTAMPS": "{}"}

0 commit comments

Comments
 (0)