From c3c1e0c0807a3df1852bb9c30ba6d2468a71f78d Mon Sep 17 00:00:00 2001 From: Raphael 'kena' Poss Date: Mon, 18 Jan 2021 16:35:20 +0100 Subject: [PATCH 1/2] sql: include placeholders alongside stmts in structured events When a statement uses placeholders, in order to get a full picture we need to see the placeholders alongside the statement. This was missing previously. Release note (bug fix): Placeholder value are now included alongside statements in structured events. --- docs/generated/eventlog.md | 50 ++++++++ pkg/sql/BUILD.bazel | 2 + pkg/sql/create_stats.go | 1 + pkg/sql/event_log.go | 10 +- pkg/sql/event_log_test.go | 100 ++++++++++++++++ .../logictest/testdata/logic_test/event_log | 4 +- pkg/util/log/eventpb/events.pb.go | 110 +++++++++++++----- pkg/util/log/eventpb/events.proto | 3 + pkg/util/log/eventpb/json_encode_generated.go | 19 +++ 9 files changed, 268 insertions(+), 31 deletions(-) create mode 100644 pkg/sql/event_log_test.go diff --git a/docs/generated/eventlog.md b/docs/generated/eventlog.md index e05fa7a8f91b..c88feefe2168 100644 --- a/docs/generated/eventlog.md +++ b/docs/generated/eventlog.md @@ -150,6 +150,7 @@ An event of type `set_cluster_setting` is recorded when a cluster setting is cha | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ## SQL Logical Schema Changes @@ -185,6 +186,7 @@ An event of type `alter_database_add_region` is recorded when a region is added | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `alter_database_primary_region` @@ -207,6 +209,7 @@ An event of type `alter_database_primary_region` is recorded when a primary regi | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `alter_database_survival_goal` @@ -229,6 +232,7 @@ An event of type `alter_database_survival_goal` is recorded when the survival go | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `alter_index` @@ -252,6 +256,7 @@ An event of type `alter_index` is recorded when an index is altered. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `alter_sequence` @@ -273,6 +278,7 @@ An event of type `alter_sequence` is recorded when a sequence is altered. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `alter_table` @@ -296,6 +302,7 @@ An event of type `alter_table` is recorded when a table is altered. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `alter_type` @@ -317,6 +324,7 @@ EventAlterType is recorded when a user-defined type is altered. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `comment_on_column` @@ -341,6 +349,7 @@ An event of type `comment_on_column` is recorded when a column is commented. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `comment_on_database` @@ -364,6 +373,7 @@ CommentOnTable is recorded when a database is commented. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `comment_on_index` @@ -388,6 +398,7 @@ An event of type `comment_on_index` is recorded when an index is commented. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `comment_on_table` @@ -411,6 +422,7 @@ An event of type `comment_on_table` is recorded when a table is commented. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `convert_to_schema` @@ -433,6 +445,7 @@ An event of type `convert_to_schema` is recorded when a database is converted to | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `create_database` @@ -454,6 +467,7 @@ An event of type `create_database` is recorded when a database is created. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `create_index` @@ -477,6 +491,7 @@ An event of type `create_index` is recorded when an index is created. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `create_schema` @@ -499,6 +514,7 @@ An event of type `create_schema` is recorded when a schema is created. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `create_sequence` @@ -521,6 +537,7 @@ An event of type `create_sequence` is recorded when a sequence is created. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `create_statistics` @@ -546,6 +563,7 @@ Events of this type are only collected when the cluster setting | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `create_table` @@ -568,6 +586,7 @@ An event of type `create_table` is recorded when a table is created. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `create_type` @@ -590,6 +609,7 @@ An event of type `create_type` is recorded when a user-defined type is created. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `create_view` @@ -613,6 +633,7 @@ An event of type `create_view` is recorded when a view is created. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `drop_database` @@ -635,6 +656,7 @@ An event of type `drop_database` is recorded when a database is dropped. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `drop_index` @@ -659,6 +681,7 @@ An event of type `drop_index` is recorded when an index is dropped. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `drop_schema` @@ -680,6 +703,7 @@ An event of type `drop_schema` is recorded when a schema is dropped. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `drop_sequence` @@ -701,6 +725,7 @@ An event of type `drop_sequence` is recorded when a sequence is dropped. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `drop_table` @@ -723,6 +748,7 @@ An event of type `drop_table` is recorded when a table is dropped. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `drop_type` @@ -744,6 +770,7 @@ An event of type `drop_type` is recorded when a user-defined type is dropped. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `drop_view` @@ -766,6 +793,7 @@ An event of type `drop_view` is recorded when a view is dropped. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `finish_schema_change` @@ -824,6 +852,7 @@ An event of type `rename_database` is recorded when a database is renamed. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `rename_schema` @@ -846,6 +875,7 @@ An event of type `rename_schema` is recorded when a schema is renamed. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `rename_table` @@ -868,6 +898,7 @@ An event of type `rename_table` is recorded when a table, sequence or view is re | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `rename_type` @@ -890,6 +921,7 @@ An event of type `rename_type` is recorded when a user-defined type is renamed. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `reverse_schema_change` @@ -933,6 +965,7 @@ An event of type `truncate_table` is recorded when a table is truncated. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `unsafe_delete_descriptor` @@ -962,6 +995,7 @@ patch releases without advance notice. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `unsafe_delete_namespace_entry` @@ -991,6 +1025,7 @@ patch releases without advance notice. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `unsafe_upsert_descriptor` @@ -1016,6 +1051,7 @@ using crdb_internal.unsafe_upsert_descriptor(). | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `unsafe_upsert_namespace_entry` @@ -1047,6 +1083,7 @@ patch releases without advance notice. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ## SQL Privilege changes @@ -1082,6 +1119,7 @@ An event of type `alter_database_owner` is recorded when a database's owner is c | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `alter_schema_owner` @@ -1104,6 +1142,7 @@ An event of type `alter_schema_owner` is recorded when a schema's owner is chang | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `alter_table_owner` @@ -1126,6 +1165,7 @@ An event of type `alter_table_owner` is recorded when the owner of a table, view | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `alter_type_owner` @@ -1148,6 +1188,7 @@ An event of type `alter_type_owner` is recorded when the owner of a user-defiend | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `change_database_privilege` @@ -1170,6 +1211,7 @@ added to / removed from a user for a database object. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | | `Grantee` | The user/role affected by the grant or revoke operation. | yes | | `GrantedPrivileges` | The privileges being granted to the grantee. | no | | `RevokedPrivileges` | The privileges being revoked from the grantee. | no | @@ -1195,6 +1237,7 @@ removed from a user for a schema object. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | | `Grantee` | The user/role affected by the grant or revoke operation. | yes | | `GrantedPrivileges` | The privileges being granted to the grantee. | no | | `RevokedPrivileges` | The privileges being revoked from the grantee. | no | @@ -1220,6 +1263,7 @@ from a user for a table, sequence or view object. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | | `Grantee` | The user/role affected by the grant or revoke operation. | yes | | `GrantedPrivileges` | The privileges being granted to the grantee. | no | | `RevokedPrivileges` | The privileges being revoked from the grantee. | no | @@ -1245,6 +1289,7 @@ removed from a user for a type object. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | | `Grantee` | The user/role affected by the grant or revoke operation. | yes | | `GrantedPrivileges` | The privileges being granted to the grantee. | no | | `RevokedPrivileges` | The privileges being revoked from the grantee. | no | @@ -1448,6 +1493,7 @@ An event of type `alter_role` is recorded when a role is altered. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `create_role` @@ -1469,6 +1515,7 @@ An event of type `create_role` is recorded when a role is created. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ### `drop_role` @@ -1490,6 +1537,7 @@ An event of type `drop_role` is recorded when a role is dropped. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | ## Zone config events @@ -1524,6 +1572,7 @@ An event of type `remove_zone_config` is recorded when a zone config is removed. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | | `Target` | The target object of the zone config change. | yes | | `Config` | The applied zone config in YAML format. | yes | | `Options` | The SQL representation of the applied zone config options. | yes | @@ -1545,6 +1594,7 @@ An event of type `set_zone_config` is recorded when a zone config is changed. | `User` | The user account that triggered the event. | yes | | `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | | `Target` | The target object of the zone config change. | yes | | `Config` | The applied zone config in YAML format. | yes | | `Options` | The SQL representation of the applied zone config options. | yes | diff --git a/pkg/sql/BUILD.bazel b/pkg/sql/BUILD.bazel index 47c4148118ff..8daa8d602419 100644 --- a/pkg/sql/BUILD.bazel +++ b/pkg/sql/BUILD.bazel @@ -412,6 +412,7 @@ go_test( "drop_helpers_test.go", "drop_test.go", "err_count_test.go", + "event_log_test.go", "explain_bundle_test.go", "explain_test.go", "explain_tree_test.go", @@ -555,6 +556,7 @@ go_test( "//pkg/util/json", "//pkg/util/leaktest", "//pkg/util/log", + "//pkg/util/log/eventpb", "//pkg/util/metric", "//pkg/util/mon", "//pkg/util/protoutil", diff --git a/pkg/sql/create_stats.go b/pkg/sql/create_stats.go index 65b006d84646..53fb7a3cc4b8 100644 --- a/pkg/sql/create_stats.go +++ b/pkg/sql/create_stats.go @@ -567,6 +567,7 @@ func (r *createStatsResumer) Resume(ctx context.Context, execCtx interface{}) er evalCtx.SessionData.User(), evalCtx.SessionData.ApplicationName, details.Statement, + nil, /* no placeholders known at this point */ &eventpb.CreateStatistics{ TableName: details.FQTableName, }) diff --git a/pkg/sql/event_log.go b/pkg/sql/event_log.go index de506cd71996..962f1154f4fe 100644 --- a/pkg/sql/event_log.go +++ b/pkg/sql/event_log.go @@ -34,9 +34,10 @@ func (p *planner) logEvent( // Compute the common fields from data already known to the planner. user := p.User() stmt := tree.AsStringWithFQNames(p.stmt.AST, p.extendedEvalCtx.EvalContext.Annotations) + pl := p.extendedEvalCtx.EvalContext.Placeholders.Values appName := p.SessionData().ApplicationName - return logEventInternalForSQLStatements(ctx, p.extendedEvalCtx.ExecCfg, p.txn, descID, user, appName, stmt, event) + return logEventInternalForSQLStatements(ctx, p.extendedEvalCtx.ExecCfg, p.txn, descID, user, appName, stmt, pl, event) } // logEventInternalForSchemaChange emits a cluster event in the @@ -83,6 +84,7 @@ func logEventInternalForSQLStatements( user security.SQLUsername, appName string, stmt string, + placeholders tree.QueryArguments, event eventpb.EventPayload, ) error { // Inject the common fields into the payload provided by the caller. @@ -96,6 +98,12 @@ func logEventInternalForSQLStatements( m.ApplicationName = appName m.User = user.Normalized() m.DescriptorID = uint32(descID) + if len(placeholders) > 0 { + m.PlaceholderValues = make([]string, len(placeholders)) + for idx, val := range placeholders { + m.PlaceholderValues[idx] = val.String() + } + } // Delegate the storing of the event to the regular event logic. return InsertEventRecord(ctx, execCfg.InternalExecutor, diff --git a/pkg/sql/event_log_test.go b/pkg/sql/event_log_test.go new file mode 100644 index 000000000000..707246c4017e --- /dev/null +++ b/pkg/sql/event_log_test.go @@ -0,0 +1,100 @@ +// Copyright 2020 The Cockroach Authors. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package sql_test + +import ( + "context" + "encoding/json" + "math" + "reflect" + "regexp" + "strings" + "testing" + + "github.com/cockroachdb/cockroach/pkg/base" + "github.com/cockroachdb/cockroach/pkg/testutils/serverutils" + "github.com/cockroachdb/cockroach/pkg/util/leaktest" + "github.com/cockroachdb/cockroach/pkg/util/log" + "github.com/cockroachdb/cockroach/pkg/util/log/eventpb" + "github.com/cockroachdb/cockroach/pkg/util/timeutil" + "github.com/cockroachdb/redact" +) + +func TestStructuredEventLogging(t *testing.T) { + defer leaktest.AfterTest(t)() + + // We really need to have the logs go to files, so that -show-logs + // does not break the "authlog" directives. + sc := log.ScopeWithoutShowLogs(t) + defer sc.Close(t) + + ctx := context.Background() + + s, conn, _ := serverutils.StartServer(t, base.TestServerArgs{}) + defer s.Stopper().Stop(ctx) + + testStartTs := timeutil.Now() + + // Make a prepared statement that changes a cluster setting: + // - we want a prepared statement to verify that the reporting of + // placeholders works during EXECUTE. + // - we don't care about the particular cluster setting; any + // setting that does not otherwise impact the test's semantics + // will do. + const setStmt = `SET CLUSTER SETTING "sql.defaults.default_int_size" = $1` + if _, err := conn.ExecContext(ctx, + `PREPARE a(INT) AS `+setStmt, + ); err != nil { + t.Fatal(err) + } + // Run the prepared statement. This triggers a structured entry + // for the cluster setting change. + if _, err := conn.ExecContext(ctx, `EXECUTE a(8)`); err != nil { + t.Fatal(err) + } + + // Ensure that the entries hit the OS so they can be read back below. + log.Flush() + + entries, err := log.FetchEntriesFromFiles(testStartTs.UnixNano(), + math.MaxInt64, 10000, execLogRe, log.WithMarkedSensitiveData) + if err != nil { + t.Fatal(err) + } + + foundEntry := false + for _, e := range entries { + if !strings.Contains(e.Message, "set_cluster_setting") { + continue + } + foundEntry = true + // TODO(knz): Remove this when crdb-v2 becomes the new format. + e.Message = strings.TrimPrefix(e.Message, "Structured entry:") + // crdb-v2 starts json with an equal sign. + e.Message = strings.TrimPrefix(e.Message, "=") + jsonPayload := []byte(e.Message) + var ev eventpb.SetClusterSetting + if err := json.Unmarshal(jsonPayload, &ev); err != nil { + t.Errorf("unmarshalling %q: %v", e.Message, err) + } + if expected := string(redact.Sprint(setStmt)); ev.Statement != expected { + t.Errorf("wrong statement: expected %q, got %q", expected, ev.Statement) + } + if expected := []string{string(redact.Sprint("8"))}; !reflect.DeepEqual(expected, ev.PlaceholderValues) { + t.Errorf("wrong placeholders: expected %+v, got %+v", expected, ev.PlaceholderValues) + } + } + if !foundEntry { + t.Error("structured entry for set_cluster_setting not found in log") + } +} + +var execLogRe = regexp.MustCompile(`event_log.go`) diff --git a/pkg/sql/logictest/testdata/logic_test/event_log b/pkg/sql/logictest/testdata/logic_test/event_log index 6077eada8331..71beb1a0f954 100644 --- a/pkg/sql/logictest/testdata/logic_test/event_log +++ b/pkg/sql/logictest/testdata/logic_test/event_log @@ -468,11 +468,11 @@ ORDER BY "timestamp", info ---- 0 1 {"ApplicationName": "$ internal-optInToDiagnosticsStatReporting", "EventType": "set_cluster_setting", "SettingName": "diagnostics.reporting.enabled", "Statement": "SET CLUSTER SETTING \"diagnostics.reporting.enabled\" = true", "User": "root", "Value": "true"} 0 1 {"EventType": "set_cluster_setting", "SettingName": "kv.range_merge.queue_enabled", "Statement": "SET CLUSTER SETTING \"kv.range_merge.queue_enabled\" = false", "User": "root", "Value": "false"} -0 1 {"EventType": "set_cluster_setting", "SettingName": "sql.stats.automatic_collection.min_stale_rows", "Statement": "SET CLUSTER SETTING \"sql.stats.automatic_collection.min_stale_rows\" = $1::INT8", "User": "root", "Value": "5"} +0 1 {"EventType": "set_cluster_setting", "PlaceholderValues": ["5"], "SettingName": "sql.stats.automatic_collection.min_stale_rows", "Statement": "SET CLUSTER SETTING \"sql.stats.automatic_collection.min_stale_rows\" = $1::INT8", "User": "root", "Value": "5"} 0 1 {"EventType": "set_cluster_setting", "SettingName": "sql.defaults.interleaved_tables.enabled", "Statement": "SET CLUSTER SETTING \"sql.defaults.interleaved_tables.enabled\" = true", "User": "root", "Value": "true"} 0 1 {"EventType": "set_cluster_setting", "SettingName": "kv.allocator.load_based_lease_rebalancing.enabled", "Statement": "SET CLUSTER SETTING \"kv.allocator.load_based_lease_rebalancing.enabled\" = false", "User": "root", "Value": "false"} 0 1 {"EventType": "set_cluster_setting", "SettingName": "kv.allocator.load_based_lease_rebalancing.enabled", "Statement": "SET CLUSTER SETTING \"kv.allocator.load_based_lease_rebalancing.enabled\" = DEFAULT", "User": "root", "Value": "DEFAULT"} -0 1 {"EventType": "set_cluster_setting", "SettingName": "cluster.organization", "Statement": "SET CLUSTER SETTING \"cluster.organization\" = $1", "User": "root", "Value": "'some string'"} +0 1 {"EventType": "set_cluster_setting", "PlaceholderValues": ["'some string'"], "SettingName": "cluster.organization", "Statement": "SET CLUSTER SETTING \"cluster.organization\" = $1", "User": "root", "Value": "'some string'"} # Set and unset zone configs ################## diff --git a/pkg/util/log/eventpb/events.pb.go b/pkg/util/log/eventpb/events.pb.go index c562b489cbd3..1591fe491fd7 100644 --- a/pkg/util/log/eventpb/events.pb.go +++ b/pkg/util/log/eventpb/events.pb.go @@ -33,7 +33,7 @@ func (m *CommonEventDetails) Reset() { *m = CommonEventDetails{} } func (m *CommonEventDetails) String() string { return proto.CompactTextString(m) } func (*CommonEventDetails) ProtoMessage() {} func (*CommonEventDetails) Descriptor() ([]byte, []int) { - return fileDescriptor_events_bc33ca9fad1c48ba, []int{0} + return fileDescriptor_events_584d902029f1b16a, []int{0} } func (m *CommonEventDetails) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -72,13 +72,15 @@ type CommonSQLEventDetails struct { // This is included in the event to ease filtering of logging output // by application. ApplicationName string `protobuf:"bytes,4,opt,name=application_name,json=applicationName,proto3" json:",omitempty"` + // The mapping of SQL placeholders to their values, for prepared statements. + PlaceholderValues []string `protobuf:"bytes,5,rep,name=placeholder_values,json=placeholderValues,proto3" json:",omitempty"` } func (m *CommonSQLEventDetails) Reset() { *m = CommonSQLEventDetails{} } func (m *CommonSQLEventDetails) String() string { return proto.CompactTextString(m) } func (*CommonSQLEventDetails) ProtoMessage() {} func (*CommonSQLEventDetails) Descriptor() ([]byte, []int) { - return fileDescriptor_events_bc33ca9fad1c48ba, []int{1} + return fileDescriptor_events_584d902029f1b16a, []int{1} } func (m *CommonSQLEventDetails) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -174,6 +176,21 @@ func (m *CommonSQLEventDetails) MarshalTo(dAtA []byte) (int, error) { i = encodeVarintEvents(dAtA, i, uint64(len(m.ApplicationName))) i += copy(dAtA[i:], m.ApplicationName) } + if len(m.PlaceholderValues) > 0 { + for _, s := range m.PlaceholderValues { + dAtA[i] = 0x2a + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) + } + } return i, nil } @@ -223,6 +240,12 @@ func (m *CommonSQLEventDetails) Size() (n int) { if l > 0 { n += 1 + l + sovEvents(uint64(l)) } + if len(m.PlaceholderValues) > 0 { + for _, s := range m.PlaceholderValues { + l = len(s) + n += 1 + l + sovEvents(uint64(l)) + } + } return n } @@ -472,6 +495,35 @@ func (m *CommonSQLEventDetails) Unmarshal(dAtA []byte) error { } m.ApplicationName = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PlaceholderValues", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PlaceholderValues = append(m.PlaceholderValues, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipEvents(dAtA[iNdEx:]) @@ -599,32 +651,34 @@ var ( ) func init() { - proto.RegisterFile("util/log/eventpb/events.proto", fileDescriptor_events_bc33ca9fad1c48ba) + proto.RegisterFile("util/log/eventpb/events.proto", fileDescriptor_events_584d902029f1b16a) } -var fileDescriptor_events_bc33ca9fad1c48ba = []byte{ - // 365 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x91, 0xc1, 0xaa, 0xd3, 0x40, - 0x14, 0x86, 0x33, 0xde, 0x8b, 0x92, 0xe1, 0x5e, 0x95, 0xe0, 0x85, 0x50, 0x70, 0x52, 0xb2, 0xb1, - 0xc2, 0x25, 0x59, 0xb8, 0xd2, 0x65, 0x5a, 0x85, 0x82, 0x08, 0x56, 0x57, 0x6e, 0xca, 0x34, 0x39, - 0xc6, 0xc1, 0xcc, 0x9c, 0x21, 0x73, 0x5a, 0xe8, 0x2b, 0xb8, 0xf2, 0xb1, 0xba, 0xec, 0xb2, 0xab, - 0xa2, 0xe9, 0x4a, 0x97, 0x3e, 0x81, 0x34, 0x29, 0xad, 0x56, 0x57, 0x33, 0xc3, 0xf9, 0xfe, 0x39, - 0x1f, 0xfc, 0xfc, 0xf1, 0x9c, 0x54, 0x95, 0x56, 0x58, 0xa6, 0xb0, 0x00, 0x43, 0x76, 0xd6, 0x9d, - 0x2e, 0xb1, 0x35, 0x12, 0x06, 0xbd, 0x1c, 0xf3, 0xcf, 0x35, 0xca, 0xfc, 0x53, 0xb2, 0x07, 0x93, - 0x0a, 0xcb, 0xe4, 0x00, 0xf6, 0x1e, 0x95, 0x58, 0x62, 0x8b, 0xa5, 0xfb, 0x5b, 0x97, 0xe8, 0x45, - 0x25, 0x62, 0x59, 0x41, 0xda, 0xbe, 0x66, 0xf3, 0x8f, 0x29, 0x29, 0x0d, 0x8e, 0xa4, 0xb6, 0x1d, - 0x10, 0x7f, 0x61, 0x3c, 0x18, 0xa2, 0xd6, 0x68, 0x5e, 0xee, 0x3f, 0x1a, 0x01, 0x49, 0x55, 0xb9, - 0xe0, 0x96, 0xfb, 0x47, 0x32, 0x64, 0x7d, 0x36, 0xb8, 0xc8, 0xee, 0xff, 0xdc, 0x46, 0xfc, 0x16, - 0xb5, 0x22, 0xd0, 0x96, 0x96, 0x93, 0x13, 0x10, 0xbc, 0xe2, 0xbc, 0xd5, 0x98, 0xd2, 0xd2, 0x42, - 0x78, 0xa7, 0xcf, 0x06, 0x7e, 0xf6, 0xe4, 0x6f, 0xfc, 0xd7, 0x36, 0xba, 0xa9, 0xa1, 0x90, 0x39, - 0xbd, 0x88, 0x0d, 0x1a, 0x07, 0xc6, 0x29, 0x52, 0x0b, 0x88, 0x27, 0x7e, 0x1b, 0x7d, 0xbf, 0xb4, - 0x10, 0xff, 0x60, 0xfc, 0xa6, 0x93, 0x79, 0xf7, 0xf6, 0xf5, 0xb9, 0x8f, 0x23, 0x49, 0xa0, 0xc1, - 0x50, 0xeb, 0xe3, 0xff, 0xeb, 0x73, 0x04, 0x82, 0x98, 0x5f, 0xce, 0x1d, 0xd4, 0x07, 0x93, 0x73, - 0xb0, 0x9d, 0x05, 0x43, 0x7e, 0x5d, 0x80, 0xcb, 0x6b, 0x65, 0x09, 0xeb, 0xa9, 0x2a, 0xc2, 0x8b, - 0x3e, 0x1b, 0x5c, 0x67, 0xa2, 0xd9, 0x46, 0x57, 0xa3, 0xe3, 0x60, 0x3c, 0x3a, 0x0b, 0x5f, 0x9d, - 0x42, 0xe3, 0x22, 0x78, 0xce, 0x1f, 0x4a, 0x6b, 0x2b, 0x95, 0x4b, 0x52, 0x68, 0xa6, 0x46, 0x6a, - 0x08, 0x2f, 0xff, 0xbb, 0xf4, 0xc1, 0x1f, 0xdc, 0x1b, 0xa9, 0x21, 0x7b, 0xba, 0xfa, 0x2e, 0xbc, - 0x55, 0x23, 0xd8, 0xba, 0x11, 0x6c, 0xd3, 0x08, 0xf6, 0xad, 0x11, 0xec, 0xeb, 0x4e, 0x78, 0xeb, - 0x9d, 0xf0, 0x36, 0x3b, 0xe1, 0x7d, 0xb8, 0x77, 0xa8, 0x76, 0x76, 0xb7, 0xad, 0xea, 0xd9, 0xef, - 0x00, 0x00, 0x00, 0xff, 0xff, 0xce, 0x64, 0xc0, 0x0f, 0x1e, 0x02, 0x00, 0x00, +var fileDescriptor_events_584d902029f1b16a = []byte{ + // 398 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0xd2, 0x4f, 0x8b, 0x13, 0x31, + 0x18, 0x06, 0xf0, 0x66, 0xbb, 0x2a, 0x0d, 0xbb, 0xfe, 0x09, 0x2e, 0x0c, 0x05, 0xd3, 0x32, 0x17, + 0x2b, 0x2c, 0x9d, 0x83, 0x27, 0x05, 0x2f, 0xdd, 0x2a, 0x2c, 0x88, 0xe0, 0x2a, 0x1e, 0xbc, 0x94, + 0x74, 0xe6, 0x75, 0x36, 0x98, 0xe4, 0x0d, 0x93, 0xb7, 0x85, 0x7e, 0x05, 0x4f, 0x7e, 0x0c, 0x3f, + 0xca, 0x1e, 0xf7, 0xb8, 0xa7, 0xa2, 0xd3, 0x9b, 0x47, 0x3f, 0x81, 0x34, 0x53, 0xba, 0x6b, 0xdd, + 0xd3, 0x4c, 0x78, 0x7f, 0x4f, 0xf2, 0x40, 0xc2, 0x9f, 0xcc, 0x48, 0x9b, 0xcc, 0x60, 0x99, 0xc1, + 0x1c, 0x1c, 0xf9, 0x69, 0xf3, 0x0d, 0x43, 0x5f, 0x21, 0xa1, 0xe8, 0xe6, 0x98, 0x7f, 0xad, 0x50, + 0xe5, 0xe7, 0xc3, 0x35, 0x1c, 0x1a, 0x2c, 0x87, 0x1b, 0xd8, 0x7d, 0x5c, 0x62, 0x89, 0x91, 0x65, + 0xeb, 0xbf, 0x26, 0xd1, 0xed, 0x95, 0x88, 0xa5, 0x81, 0x2c, 0xae, 0xa6, 0xb3, 0x2f, 0x19, 0x69, + 0x0b, 0x81, 0x94, 0xf5, 0x0d, 0x48, 0xbf, 0x31, 0x2e, 0x4e, 0xd0, 0x5a, 0x74, 0xaf, 0xd7, 0x1b, + 0x8d, 0x81, 0x94, 0x36, 0x41, 0x1c, 0xf3, 0xce, 0x56, 0x26, 0xac, 0xcf, 0x06, 0xed, 0xd1, 0xfd, + 0xdf, 0xcb, 0x1e, 0x3f, 0x46, 0xab, 0x09, 0xac, 0xa7, 0xc5, 0xd9, 0x35, 0x10, 0x6f, 0x38, 0x8f, + 0x35, 0x26, 0xb4, 0xf0, 0x90, 0xec, 0xf5, 0xd9, 0xa0, 0x33, 0x7a, 0xfa, 0x2f, 0xff, 0xb3, 0xec, + 0x1d, 0x55, 0x50, 0xa8, 0x9c, 0x5e, 0xa6, 0x0e, 0x5d, 0x00, 0x17, 0x34, 0xe9, 0x39, 0xa4, 0x67, + 0x9d, 0x18, 0xfd, 0xb8, 0xf0, 0x90, 0xfe, 0xd8, 0xe3, 0x47, 0x4d, 0x99, 0x0f, 0xef, 0xdf, 0xee, + 0xf6, 0x09, 0xa4, 0x08, 0x2c, 0x38, 0x8a, 0x7d, 0x3a, 0xff, 0xf7, 0xd9, 0x02, 0x91, 0xf2, 0xfd, + 0x59, 0x80, 0x6a, 0xd3, 0x64, 0x17, 0xc6, 0x99, 0x38, 0xe1, 0x87, 0x05, 0x84, 0xbc, 0xd2, 0x9e, + 0xb0, 0x9a, 0xe8, 0x22, 0x69, 0xf7, 0xd9, 0xe0, 0x70, 0x24, 0xeb, 0x65, 0xef, 0x60, 0xbc, 0x1d, + 0x9c, 0x8e, 0x77, 0xc2, 0x07, 0xd7, 0xa1, 0xd3, 0x42, 0xbc, 0xe0, 0x0f, 0x95, 0xf7, 0x46, 0xe7, + 0x8a, 0x34, 0xba, 0x89, 0x53, 0x16, 0x92, 0xfd, 0x5b, 0x0f, 0x7d, 0x70, 0xc3, 0xbd, 0x53, 0x16, + 0xc4, 0x2b, 0x2e, 0xbc, 0x51, 0x39, 0x9c, 0xa3, 0x29, 0xa0, 0x9a, 0xcc, 0x95, 0x99, 0x41, 0x48, + 0xee, 0xf4, 0xdb, 0xb7, 0x84, 0x1f, 0xdd, 0x90, 0x9f, 0x22, 0x1c, 0x3d, 0xbb, 0xf8, 0x25, 0x5b, + 0x17, 0xb5, 0x64, 0x97, 0xb5, 0x64, 0x57, 0xb5, 0x64, 0x3f, 0x6b, 0xc9, 0xbe, 0xaf, 0x64, 0xeb, + 0x72, 0x25, 0x5b, 0x57, 0x2b, 0xd9, 0xfa, 0x7c, 0x6f, 0xf3, 0x32, 0xa6, 0x77, 0xe3, 0x4d, 0x3f, + 0xff, 0x1b, 0x00, 0x00, 0xff, 0xff, 0xa4, 0x2e, 0x27, 0xfb, 0x5d, 0x02, 0x00, 0x00, } diff --git a/pkg/util/log/eventpb/events.proto b/pkg/util/log/eventpb/events.proto index dfdabba05af6..1d7d99131676 100644 --- a/pkg/util/log/eventpb/events.proto +++ b/pkg/util/log/eventpb/events.proto @@ -48,5 +48,8 @@ message CommonSQLEventDetails { // This is included in the event to ease filtering of logging output // by application. string application_name = 4 [(gogoproto.jsontag) = ",omitempty"]; + + // The mapping of SQL placeholders to their values, for prepared statements. + repeated string placeholder_values = 5 [(gogoproto.jsontag) = ",omitempty"]; } diff --git a/pkg/util/log/eventpb/json_encode_generated.go b/pkg/util/log/eventpb/json_encode_generated.go index b732a4ff67f0..17177988ccd2 100644 --- a/pkg/util/log/eventpb/json_encode_generated.go +++ b/pkg/util/log/eventpb/json_encode_generated.go @@ -1027,6 +1027,25 @@ func (m *CommonSQLEventDetails) AppendJSONFields(printComma bool, b redact.Redac b = append(b, '"') } + if len(m.PlaceholderValues) > 0 { + if printComma { + b = append(b, ',') + } + printComma = true + b = append(b, "\"PlaceholderValues\":["...) + for i, v := range m.PlaceholderValues { + if i > 0 { + b = append(b, ',') + } + b = append(b, '"') + b = append(b, redact.StartMarker()...) + b = redact.RedactableBytes(jsonbytes.EncodeString([]byte(b), string(redact.EscapeMarkers([]byte(v))))) + b = append(b, redact.EndMarker()...) + b = append(b, '"') + } + b = append(b, ']') + } + return printComma, b } From 253bff3ef53ead41511c5a73db4251bedeef444d Mon Sep 17 00:00:00 2001 From: Raphael 'kena' Poss Date: Mon, 21 Dec 2020 18:20:18 +0100 Subject: [PATCH 2/2] sql: convert SQL audit and execution log to a structured format Example new format for the query log: ``` I210118 17:20:32.675052 2009 10@util/log/event_log.go:32 [n1,client=127.0.0.1:11362,hostssl,user=demo] Structured entry: {"Timestamp":1610990432674339786, "EventType":"slow_query", "Statement":"SELECT * FROM \"\".\"\".t WHERE x = 10", "User":"demo", "ApplicationName":"$ cockroach demo", "ExecMode":"exec", "Age":0.790742, "FullTableScan":true} ``` Example new format, for audit events: ``` I210122 16:33:01.297735 2012 8@util/log/event_log.go:32 [n1,client=127.0.0.1:59820,hostssl,user=demo] Structured entry: {"Timestamp":1611333181296915618, "EventType":"sensitive_table_access", "Statement":"INSERT INTO \"\".\"\".helloworld(abc) VALUES (1)", "User":"demo", "DescriptorID":53, "ApplicationName":"$ cockroach demo", "ExecMode":"exec", "NumRows":1, "Age":0.895012, "TableName":"t.public.helloworld", "AccessMode":"rw"} ``` (Audit events have more fields, specifically `DescriptorID`, `TableName` and `AccessMode`, because they pertain to specific objects for which audit logging has been triggered.) Release note (sql change): CockroachDB now uses a structured logging format for the SQL audit, execution and query logs. See the reference documentation for details. Of note, audit and execution logs now also include information about whether a query plan contain full index scans. Previously, this information was only included in theslow query log. Release note (backward-incompatible change): The logging format for SQL audit, execution and query logs has changed, from a crude space-delimited format to JSON. To opt out of this new behavior and restore the pre-v21.1 logging format, you can set the cluster setting `sql.log.unstructured_entries.enabled` to true. --- Makefile | 1 + docs/generated/eventlog.md | 174 ++ pkg/cli/interactive_tests/test_audit_log.tcl | 13 +- pkg/server/node.go | 4 +- pkg/server/server.go | 4 +- pkg/sql/create_stats.go | 4 +- pkg/sql/event_log.go | 43 +- pkg/sql/exec_log.go | 257 ++- pkg/util/log/eventpb/BUILD.bazel | 1 + .../eventpb/eventlog_channels_generated.go | 12 + pkg/util/log/eventpb/gen.go | 14 +- pkg/util/log/eventpb/json_encode_generated.go | 151 ++ pkg/util/log/eventpb/sql_audit_events.pb.go | 1613 +++++++++++++++++ pkg/util/log/eventpb/sql_audit_events.proto | 131 ++ 14 files changed, 2320 insertions(+), 102 deletions(-) create mode 100644 pkg/util/log/eventpb/sql_audit_events.pb.go create mode 100644 pkg/util/log/eventpb/sql_audit_events.proto diff --git a/Makefile b/Makefile index 9ec87dfbc10f..24a2686c992d 100644 --- a/Makefile +++ b/Makefile @@ -1549,6 +1549,7 @@ EVENTLOG_PROTOS = \ pkg/util/log/eventpb/role_events.proto \ pkg/util/log/eventpb/zone_events.proto \ pkg/util/log/eventpb/session_events.proto \ + pkg/util/log/eventpb/sql_audit_events.proto \ pkg/util/log/eventpb/cluster_events.proto docs/generated/eventlog.md: pkg/util/log/eventpb/gen.go $(EVENTLOG_PROTOS) | bin/.go_protobuf_sources diff --git a/docs/generated/eventlog.md b/docs/generated/eventlog.md index c88feefe2168..8bf61fb533a9 100644 --- a/docs/generated/eventlog.md +++ b/docs/generated/eventlog.md @@ -152,6 +152,91 @@ An event of type `set_cluster_setting` is recorded when a cluster setting is cha | `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | | `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | +## SQL Access Audit Events + +Events in this category are generated when a table has been +marked as audited via `ALTER ... EXPERIMENTAL_AUDIT SET`. + +This feature is experimental. + +Note: these events are not written to `system.eventlog`, even +when the cluster setting `system.eventlog.enabled` is set. They +are only emitted via external logging. + +Events in this category are logged to channel SENSITIVE_ACCESS. + + +### `sensitive_table_access` + +An event of type `sensitive_table_access` is recorded when an access is performed to +a table marked as audited. + + +| Field | Description | Sensitive | +|--|--|--| +| `TableName` | The name of the table being audited. | yes | +| `AccessMode` | How the table was accessed (r=read / rw=read/write). | no | + + +#### Common fields + +| Field | Description | Sensitive | +|--|--|--| +| `Timestamp` | The timestamp of the event. Expressed as nanoseconds since the Unix epoch. | no | +| `EventType` | The type of the event. | no | +| `Statement` | A normalized copy of the SQL statement that triggered the event. | yes | +| `User` | The user account that triggered the event. | yes | +| `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | +| `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | +| `ExecMode` | How the statement was being executed (exec/prepare, etc.) | no | +| `NumRows` | Number of rows returned. For mutation statements (INSERT, etc) that do not produce result rows, this field reports the number of rows affected. | no | +| `SQLSTATE` | The SQLSTATE code for the error, if an error was encountered. Empty/omitted if no error. | no | +| `ErrorText` | The text of the error if any. | yes | +| `Age` | Age of the query in milliseconds. | no | +| `NumRetries` | Number of retries, when the txn was reretried automatically by the server. | no | +| `FullTableScan` | Whether the query contains a full table scan. | no | +| `FullIndexScan` | Whether the query contains a full secondary index scan. | no | + +## SQL Execution Log + +Events in this category report executed queries. + +Note: these events are not written to `system.eventlog`, even +when the cluster setting `system.eventlog.enabled` is set. They +are only emitted via external logging. + +Events in this category are logged to channel SQL_EXEC. + + +### `query_execute` + +An event of type `query_execute` is recorded when a query is executed, +and the cluster setting `sql.trace.log_statement_execute` is set. + + + + +#### Common fields + +| Field | Description | Sensitive | +|--|--|--| +| `Timestamp` | The timestamp of the event. Expressed as nanoseconds since the Unix epoch. | no | +| `EventType` | The type of the event. | no | +| `Statement` | A normalized copy of the SQL statement that triggered the event. | yes | +| `User` | The user account that triggered the event. | yes | +| `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | +| `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | +| `ExecMode` | How the statement was being executed (exec/prepare, etc.) | no | +| `NumRows` | Number of rows returned. For mutation statements (INSERT, etc) that do not produce result rows, this field reports the number of rows affected. | no | +| `SQLSTATE` | The SQLSTATE code for the error, if an error was encountered. Empty/omitted if no error. | no | +| `ErrorText` | The text of the error if any. | yes | +| `Age` | Age of the query in milliseconds. | no | +| `NumRetries` | Number of retries, when the txn was reretried automatically by the server. | no | +| `FullTableScan` | Whether the query contains a full table scan. | no | +| `FullIndexScan` | Whether the query contains a full secondary index scan. | no | + ## SQL Logical Schema Changes Events in this category pertain to DDL (Data Definition Language) @@ -1460,6 +1545,95 @@ Events of this type are only emitted when the cluster setting | `Transport` | The connection type after transport negotiation. | no | | `User` | The username the session is for. This is the username passed by the client, after case-folding and Unicode normalization. | yes | +## SQL Slow Query Log + +Events in this category report slow query execution. + +Note: these events are not written to `system.eventlog`, even +when the cluster setting `system.eventlog.enabled` is set. They +are only emitted via external logging. + +Events in this category are logged to channel SQL_PERF. + + +### `slow_query` + +An event of type `slow_query` is recorded when a query triggers the "slow query" condition. + +As of this writing, the condition requires: +- the cluster setting `sql.log.slow_query.latency_threshold` +set to a non-zero value, AND +- EITHER of the following conditions: +- the actual age of the query exceeds the configured threshold; OR +- the query performs a full table/index scan. + + + + +#### Common fields + +| Field | Description | Sensitive | +|--|--|--| +| `Timestamp` | The timestamp of the event. Expressed as nanoseconds since the Unix epoch. | no | +| `EventType` | The type of the event. | no | +| `Statement` | A normalized copy of the SQL statement that triggered the event. | yes | +| `User` | The user account that triggered the event. | yes | +| `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | +| `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | +| `ExecMode` | How the statement was being executed (exec/prepare, etc.) | no | +| `NumRows` | Number of rows returned. For mutation statements (INSERT, etc) that do not produce result rows, this field reports the number of rows affected. | no | +| `SQLSTATE` | The SQLSTATE code for the error, if an error was encountered. Empty/omitted if no error. | no | +| `ErrorText` | The text of the error if any. | yes | +| `Age` | Age of the query in milliseconds. | no | +| `NumRetries` | Number of retries, when the txn was reretried automatically by the server. | no | +| `FullTableScan` | Whether the query contains a full table scan. | no | +| `FullIndexScan` | Whether the query contains a full secondary index scan. | no | + +## SQL Slow Query Log (Internal) + +Events in this category report slow query execution by +internal executors, i.e. when CockroachDB internally issues +SQL statements. + +Note: these events are not written to `system.eventlog`, even +when the cluster setting `system.eventlog.enabled` is set. They +are only emitted via external logging. + +Events in this category are logged to channel SQL_INTERNAL_PERF. + + +### `slow_query_internal` + +An event of type `slow_query_internal` is recorded when a query triggers the "slow query" condition, +and the cluster setting `sql.log.slow_query.internal_queries.enabled` is +set. +See the documentation for the event type `slow_query` for details about +the "slow query" condition. + + + + +#### Common fields + +| Field | Description | Sensitive | +|--|--|--| +| `Timestamp` | The timestamp of the event. Expressed as nanoseconds since the Unix epoch. | no | +| `EventType` | The type of the event. | no | +| `Statement` | A normalized copy of the SQL statement that triggered the event. | yes | +| `User` | The user account that triggered the event. | yes | +| `DescriptorID` | The primary object descriptor affected by the operation. Set to zero for operations that don't affect descriptors. | no | +| `ApplicationName` | The application name for the session where the event was emitted. This is included in the event to ease filtering of logging output by application. | yes | +| `PlaceholderValues` | The mapping of SQL placeholders to their values, for prepared statements. | yes | +| `ExecMode` | How the statement was being executed (exec/prepare, etc.) | no | +| `NumRows` | Number of rows returned. For mutation statements (INSERT, etc) that do not produce result rows, this field reports the number of rows affected. | no | +| `SQLSTATE` | The SQLSTATE code for the error, if an error was encountered. Empty/omitted if no error. | no | +| `ErrorText` | The text of the error if any. | yes | +| `Age` | Age of the query in milliseconds. | no | +| `NumRetries` | Number of retries, when the txn was reretried automatically by the server. | no | +| `FullTableScan` | Whether the query contains a full table scan. | no | +| `FullIndexScan` | Whether the query contains a full secondary index scan. | no | + ## SQL User and Role operations Events in this category pertain to SQL statements that modify the diff --git a/pkg/cli/interactive_tests/test_audit_log.tcl b/pkg/cli/interactive_tests/test_audit_log.tcl index 7d303fb2e7af..a6da43a27435 100644 --- a/pkg/cli/interactive_tests/test_audit_log.tcl +++ b/pkg/cli/interactive_tests/test_audit_log.tcl @@ -23,22 +23,25 @@ start_test "Check that statements start being logged synchronously if auditing i send "ALTER TABLE helloworld EXPERIMENTAL_AUDIT SET READ WRITE;\r" eexpect root@ # check that the audit change itself is recorded. -system "grep -q 'helloworld.*:READWRITE.*ALTER TABLE.*OK' $logfile" +# Note: we really would like to check for redaction markers here, alas this grep +# command is running inside the acceptance image and does not know about UTF-8. +# So we use an imprecise match instead. +system "grep -q 'sensitive_table_access.*ALTER TABLE.*helloworld.*\"TableName\":\".*t.public.helloworld.*\",\"AccessMode\":\"rw\"' $logfile" send "SELECT * FROM helloworld;\r" eexpect root@ -system "grep -q 'helloworld.*:READ}.*SELECT.*OK' $logfile" +system "grep -q 'sensitive_table_access.*SELECT.*helloworld.*\"TableName\":\".*t.public.helloworld.*\",\"AccessMode\":\"r\"' $logfile" end_test start_test "Check that write statements are logged differently" send "INSERT INTO helloworld VALUES(456);\r" eexpect root@ -system "grep -q 'helloworld.*:READWRITE.*INSERT.*OK' $logfile" +system "grep -q 'sensitive_table_access.*INSERT.*helloworld.*AccessMode\":\"rw\"' $logfile" end_test start_test "Check that errors get logged too" send "SELECT nonexistent FROM helloworld;\r" eexpect root@ -system "grep -q 'helloworld.*:READ}.*SELECT.*ERROR' $logfile" +system "grep -q 'sensitive_table_access.*SELECT.*nonexistent.*SQLSTATE.*42703.*\"AccessMode\":\"r\"' $logfile" end_test # Flush and truncate the logs. The test below must not see the log entries that @@ -52,7 +55,7 @@ system "if grep -q helloworld $logfile; then false; fi" start_test "Check that audit removal is logged too" send "ALTER TABLE helloworld EXPERIMENTAL_AUDIT SET OFF;\r" eexpect root@ -system "grep 'helloworld.*:READWRITE.*ALTER TABLE.*SET OFF.*OK' $logfile" +system "grep -q 'sensitive_table_access.*ALTER TABLE.*helloworld.*SET OFF.*AccessMode\":\"rw\"' $logfile" end_test interrupt diff --git a/pkg/server/node.go b/pkg/server/node.go index 1358271235d8..fc2c50571472 100644 --- a/pkg/server/node.go +++ b/pkg/server/node.go @@ -825,7 +825,9 @@ func (n *Node) recordJoinEvent(ctx context.Context) { int32(n.Descriptor.NodeID), int32(n.Descriptor.NodeID), true, /* skipExternalLog - we already call log.StructuredEvent above */ - event) + event, + false, /* onlyLog */ + ) }); err != nil { log.Warningf(ctx, "%s: unable to log event %v: %v", n, event, err) } else { diff --git a/pkg/server/server.go b/pkg/server/server.go index 85fd464921a5..db1cb44c21ff 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -2137,7 +2137,9 @@ func (s *Server) Decommission( txn, int32(nodeID), int32(s.NodeID()), true, /* skipExternalLog - we already call log.StructuredEvent above */ - event) + event, + false, /* onlyLog */ + ) }); err != nil { log.Ops.Errorf(ctx, "unable to record event: %+v: %+v", event, err) } diff --git a/pkg/sql/create_stats.go b/pkg/sql/create_stats.go index 53fb7a3cc4b8..8089ec02cad0 100644 --- a/pkg/sql/create_stats.go +++ b/pkg/sql/create_stats.go @@ -570,7 +570,9 @@ func (r *createStatsResumer) Resume(ctx context.Context, execCtx interface{}) er nil, /* no placeholders known at this point */ &eventpb.CreateStatistics{ TableName: details.FQTableName, - }) + }, + true, /* writeToEventLog */ + ) }) } diff --git a/pkg/sql/event_log.go b/pkg/sql/event_log.go index 962f1154f4fe..550dc6923673 100644 --- a/pkg/sql/event_log.go +++ b/pkg/sql/event_log.go @@ -30,6 +30,26 @@ import ( // statement. func (p *planner) logEvent( ctx context.Context, descID descpb.ID, event eventpb.EventPayload, +) error { + return p.logEventWithSystemEventLogOption(ctx, descID, event, true /* writeToEventLog */) +} + +func (p *planner) logEventOnlyExternally( + ctx context.Context, descID descpb.ID, event eventpb.EventPayload, +) { + // The API contract for logEventWithSystemEventLogOption() is that it returns + // no error when system.eventlog is not written to. + _ = p.logEventWithSystemEventLogOption(ctx, descID, event, false /* writeToEventLog */) +} + +// logEventWithSystemEventLogOption is like logEvent() but it gives +// control to the caller as to whether the entry is written into +// system.eventlog. +// +// If writeToEventLog is false, this function guarantees that it +// returns no error. +func (p *planner) logEventWithSystemEventLogOption( + ctx context.Context, descID descpb.ID, event eventpb.EventPayload, writeToEventLog bool, ) error { // Compute the common fields from data already known to the planner. user := p.User() @@ -37,7 +57,7 @@ func (p *planner) logEvent( pl := p.extendedEvalCtx.EvalContext.Placeholders.Values appName := p.SessionData().ApplicationName - return logEventInternalForSQLStatements(ctx, p.extendedEvalCtx.ExecCfg, p.txn, descID, user, appName, stmt, pl, event) + return logEventInternalForSQLStatements(ctx, p.extendedEvalCtx.ExecCfg, p.txn, descID, user, appName, stmt, pl, event, writeToEventLog) } // logEventInternalForSchemaChange emits a cluster event in the @@ -68,7 +88,9 @@ func logEventInternalForSchemaChanges( int32(descID), int32(execCfg.NodeID.SQLInstanceID()), false, /* skipExternalLog */ - event) + event, + false, /* onlyLog */ + ) } // logEventInternalForSQLStatements emits a cluster event on behalf of @@ -76,6 +98,9 @@ func logEventInternalForSchemaChanges( // have access to a (*planner) and the current statement metadata. // // Note: usage of this interface should be minimized. +// +// If writeToEventLog is false, this function guarantees that it +// returns no error. func logEventInternalForSQLStatements( ctx context.Context, execCfg *ExecutorConfig, @@ -86,6 +111,7 @@ func logEventInternalForSQLStatements( stmt string, placeholders tree.QueryArguments, event eventpb.EventPayload, + writeToEventLog bool, ) error { // Inject the common fields into the payload provided by the caller. event.CommonDetails().Timestamp = txn.ReadTimestamp().WallTime @@ -111,7 +137,9 @@ func logEventInternalForSQLStatements( int32(descID), int32(execCfg.NodeID.SQLInstanceID()), false, /* skipExternalLog */ - event) + event, + !writeToEventLog, + ) } var eventLogEnabled = settings.RegisterBoolSetting( @@ -132,6 +160,9 @@ var eventLogEnabled = settings.RegisterBoolSetting( // // Note: the targetID and reportingID columns are deprecated and // should be removed after v21.1 is released. +// +// If onlyLog is set, this function guarantees that it returns no +// error. func InsertEventRecord( ctx context.Context, ex *InternalExecutor, @@ -139,6 +170,7 @@ func InsertEventRecord( targetID, reportingID int32, skipExternalLog bool, info eventpb.EventPayload, + onlyLog bool, ) error { eventType := eventpb.GetEventTypeName(info) @@ -150,6 +182,11 @@ func InsertEventRecord( return errors.AssertionFailedf("programming error: timestamp field in event not populated: %T", info) } + if onlyLog { + log.StructuredEvent(ctx, info) + return nil + } + // Ensure that the external logging sees the event when the // transaction commits. txn.AddCommitTrigger(func(ctx context.Context) { diff --git a/pkg/sql/exec_log.go b/pkg/sql/exec_log.go index 6e979a94fde0..8a32a92b70fc 100644 --- a/pkg/sql/exec_log.go +++ b/pkg/sql/exec_log.go @@ -19,45 +19,28 @@ import ( "github.com/cockroachdb/cockroach/pkg/settings" "github.com/cockroachdb/cockroach/pkg/sql/catalog" "github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb" + "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror" "github.com/cockroachdb/cockroach/pkg/sql/privilege" "github.com/cockroachdb/cockroach/pkg/util/log" + "github.com/cockroachdb/cockroach/pkg/util/log/eventpb" "github.com/cockroachdb/cockroach/pkg/util/timeutil" ) // This file contains facilities to report SQL activities to separate -// log files. +// log channels. // -// The log format is currently as follows: +// See the detailed log sink and format documentation +// (e.g. auto-generated files in docs/generated) for details about the +// general format of log entries. // -// Example audit log line: -// I180211 07:30:48.832004 317 sql/exec_log.go:90 [client=127.0.0.1:62503,user=root,n1] 13 exec "cockroach" {"ab"[53]:READ} "SELECT * FROM ab" {} 123.45 12 OK 0 -// I180211 07:30:48.832004 317 sql/exec_log.go:90 [client=127.0.0.1:62503,user=root,n1] 13 exec "cockroach" {"ab"[53]:READ} "SELECT nonexistent FROM ab" {} 0.123 12 ERROR 0 -// Example execution log: -// I180211 07:30:48.832004 317 sql/exec_log.go:90 [client=127.0.0.1:62503,user=root,n1] 13 exec "cockroach" {} "SELECT * FROM ab" {} 123.45 12 OK 0 -// I180211 07:30:48.832004 317 sql/exec_log.go:90 [client=127.0.0.1:62503,user=root,n1] 13 exec "cockroach" {} "SELECT nonexistent FROM ab" {} 0.123 0 "column \"nonexistent\" not found" 0 +// By default, the facilities in this file produce query logs +// using structured events. The payload of structured events +// is also auto-documented; see the corresponding event definitions +// for details. // -// Explanation of fields: -// I180211 07:30:48.832004 317 sql/exec_log.go:90 [client=127.0.0.1:62503,user=root,n1] 13 exec "cockroach" {"ab"[53]:READ} "SELECT nonexistent FROM ab" {} 0.123 12 ERROR 0 -// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -// \ .../ -// '- prefix generated by CockroachDB's standard log package. Contains: -// -// - date and time -// - incidentally, this data is needed for auditing. -// - goroutine ID -// - where in this file the message was generated -// - the logging tags [...] - this contains the client address, -// username, and node ID -// - tags were populated in the logging context when setting up -// the pgwire session. -// - generally useful and actually a requirement for auditing. -// - a counter for the logging entry, monotonically increasing -// from the point the process started. -// - this is a requirement for auditing too. -// -// .-----------------------------------------------------------------------------------------------------------------------------.../ -// | -// '- log message generated in this file. Includes: +// When the cluster setting `sql.log.unstructured_entries.enabled` is set +// (pre-v21.1 compatibility format, obsolete), the event payloads include +// the following fields: // // - a label indicating where the data was generated - useful for troubleshooting. // - distinguishes e.g. exec, prepare, internal-exec, etc. @@ -65,13 +48,7 @@ import ( // - required for auditing, also helps filter out messages from a specific app. // - the logging trigger. // - "{}" for execution logs: any activity is worth logging in the exec log -// - the list of triggering tables and access modes for audit -// events. This is needed for auditing. // - the full text of the query. -// - audit logs really ought to only "identify the data that's accessed but -// without revealing PII". We don't know how to separate those two things -// yet so the audit log contains the full SQL of the query even though -// this may yield PII. This may need to be addressed later. // - the placeholder values. Useful for queries using placeholders. // - "{}" when there are no placeholders. // - the query execution time in milliseconds. For troubleshooting. @@ -80,6 +57,9 @@ import ( // message upon error). Needed for auditing and troubleshooting. // - the number of times the statement was retried automatically // by the server so far. +// +// TODO(knz): Remove this documentation for the obsolete format when +// support for the format is removed, post-v21.1. // logStatementsExecuteEnabled causes the Executor to log executed // statements and, if any, resulting errors. @@ -113,6 +93,12 @@ var slowQueryLogFullTableScans = settings.RegisterBoolSetting( false, ).WithPublic() +var unstructuredQueryLog = settings.RegisterBoolSetting( + "sql.log.unstructured_entries.enabled", + "when set, SQL execution and audit logs use the pre-v21.1 unstrucured format", + false, +) + type executorType int const ( @@ -161,82 +147,173 @@ func (p *planner) maybeLogStatementInternal( auditEventsDetected := len(p.curPlan.auditEvents) != 0 if !logV && !logExecuteEnabled && !auditEventsDetected && !slowQueryLogEnabled { + // Shortcut: avoid the expense of computing anything log-related + // if logging is not enabled by configuration. return } - // Logged data, in order: - - // label passed as argument. + // Compute the pieces of data that are going to be included in logged events. + // The session's application_name. appName := p.EvalContext().SessionData.ApplicationName + // The duration of the query so far. Age is the duration expressed in milliseconds. + queryDuration := timeutil.Now().Sub(startTime) + age := float32(queryDuration.Nanoseconds()) / 1e6 + // The text of the error encountered, if the query did in fact end + // in error. + execErrStr := "" + if err != nil { + execErrStr = err.Error() + } + // The type of execution context (execute/prepare). + lbl := execType.logLabel() - logTrigger := "{}" - if auditEventsDetected { - var buf bytes.Buffer - buf.WriteByte('{') - sep := "" - for _, ev := range p.curPlan.auditEvents { - mode := "READ" - if ev.writing { - mode = "READWRITE" - } - fmt.Fprintf(&buf, "%s%q[%d]:%s", sep, ev.desc.GetName(), ev.desc.GetID(), mode) - sep = ", " + if unstructuredQueryLog.Get(&p.execCfg.Settings.SV) { + // This entire branch exists for the sake of backward + // compatibility with log parsers for v20.2 and prior. This format + // is obsolete and so this branch can be removed in v21.2. + // + // Look at the code "below" this if case for the main (default) + // logging output. + + // The statement being executed. + stmtStr := p.curPlan.stmt.AST.String() + plStr := p.extendedEvalCtx.Placeholders.Values.String() + + if logV { + // Copy to the debug log. + log.VEventf(ctx, execType.vLevel(), "%s %q %q %s %.3f %d %q %d", + lbl, appName, stmtStr, plStr, age, rows, execErrStr, numRetries) } - buf.WriteByte('}') - logTrigger = buf.String() - } - stmtStr := p.curPlan.stmt.AST.String() + // Now log! + if auditEventsDetected { + auditErrStr := "OK" + if err != nil { + auditErrStr = "ERROR" + } - plStr := p.extendedEvalCtx.Placeholders.Values.String() + var buf bytes.Buffer + buf.WriteByte('{') + sep := "" + for _, ev := range p.curPlan.auditEvents { + mode := "READ" + if ev.writing { + mode = "READWRITE" + } + fmt.Fprintf(&buf, "%s%q[%d]:%s", sep, ev.desc.GetName(), ev.desc.GetID(), mode) + sep = ", " + } + buf.WriteByte('}') + logTrigger := buf.String() - queryDuration := timeutil.Now().Sub(startTime) - age := float64(queryDuration.Nanoseconds()) / 1e6 + log.SensitiveAccess.Infof(ctx, "%s %q %s %q %s %.3f %d %s %d", + lbl, appName, logTrigger, stmtStr, plStr, age, rows, auditErrStr, numRetries) + } + if slowQueryLogEnabled && (queryDuration > slowLogThreshold || slowLogFullTableScans) { + logReason, shouldLog := p.slowQueryLogReason(queryDuration, slowLogThreshold) + + var logger log.ChannelLogger + // Non-internal queries are always logged to the slow query log. + if execType == executorTypeExec { + logger = sqlPerfLogger + } + // Internal queries that surpass the slow query log threshold should only + // be logged to the slow-internal-only log if the cluster setting dictates. + if execType == executorTypeInternal && slowInternalQueryLogEnabled { + logger = sqlPerfInternalLogger + } - // rows passed as argument. + if logger != nil && shouldLog { + logger.Infof(ctx, "%.3fms %s %q {} %q %s %d %q %d %s", + age, lbl, appName, stmtStr, plStr, rows, execErrStr, numRetries, logReason) + } + } + if logExecuteEnabled { + log.SqlExec.Infof(ctx, "%s %q {} %q %s %.3f %d %q %d", + lbl, appName, stmtStr, plStr, age, rows, execErrStr, numRetries) + } + return + } - execErrStr := "" - auditErrStr := "OK" + // New logging format in v21.1. + sqlErrState := "" if err != nil { - execErrStr = err.Error() - auditErrStr = "ERROR" + sqlErrState = pgerror.GetPGCode(err).String() } - lbl := execType.logLabel() + execDetails := eventpb.CommonSQLExecDetails{ + // Note: the current statement, application name, etc, are + // automatically populated by the shared logic in event_log.go. + ExecMode: lbl, + NumRows: uint64(rows), + SQLSTATE: sqlErrState, + ErrorText: execErrStr, + Age: age, + NumRetries: uint32(numRetries), + FullTableScan: p.curPlan.flags.IsSet(planFlagContainsFullTableScan), + FullIndexScan: p.curPlan.flags.IsSet(planFlagContainsFullIndexScan), + } - // Now log! - if auditEventsDetected { - log.SensitiveAccess.Infof(ctx, "%s %q %s %q %s %.3f %d %s %d", - lbl, appName, logTrigger, stmtStr, plStr, age, rows, auditErrStr, numRetries) + if logV { + // Copy to the debug log / trace. + log.VEventf(ctx, execType.vLevel(), "%+v", execDetails) } - if slowQueryLogEnabled && (queryDuration > slowLogThreshold || slowLogFullTableScans) { - logReason, shouldLog := p.slowQueryLogReason(queryDuration, slowLogThreshold) - var logger log.ChannelLogger - // Non-internal queries are always logged to the slow query log. - if execType == executorTypeExec { - logger = sqlPerfLogger - } - // Internal queries that surpass the slow query log threshold should only - // be logged to the slow-internal-only log if the cluster setting dictates. - if execType == executorTypeInternal && slowInternalQueryLogEnabled { - logger = sqlPerfInternalLogger - } + if auditEventsDetected { + // TODO(knz): re-add the placeholders and age into the logging event. + for _, ev := range p.curPlan.auditEvents { + mode := "r" + if ev.writing { + mode = "rw" + } + tableName := "" + if t, ok := ev.desc.(catalog.TableDescriptor); ok { + // We only have a valid *table* name if the object being + // audited is table-like (includes view, sequence etc). For + // now, this is sufficient because the auditing feature can + // only audit tables. If/when the mechanisms are extended to + // audit databases and schema, we need more logic here to + // extract a name to include in the logging events. + tn, err := p.getQualifiedTableName(ctx, t) + if err != nil { + log.Warningf(ctx, "name for audited table ID %d not found: %v", ev.desc.GetID(), err) + } else { + tableName = tn.FQString() + } + } - if logger != nil && shouldLog { - logger.Infof(ctx, "%.3fms %s %q %s %q %s %d %q %d %s", - age, lbl, appName, logTrigger, stmtStr, plStr, rows, execErrStr, numRetries, logReason) + p.logEventOnlyExternally(ctx, ev.desc.GetID(), + &eventpb.SensitiveTableAccess{ + CommonSQLExecDetails: execDetails, + TableName: tableName, + AccessMode: mode, + }) } } - if logExecuteEnabled { - log.SqlExec.Infof(ctx, "%s %q %s %q %s %.3f %d %q %d", - lbl, appName, logTrigger, stmtStr, plStr, age, rows, execErrStr, numRetries) + if slowQueryLogEnabled && ( + // Did the user request pumping queries into the slow query log when + // the logical plan has full scans? + (slowLogFullTableScans && (execDetails.FullTableScan || execDetails.FullIndexScan)) || + // Is the query actually slow? + queryDuration > slowLogThreshold) { + switch { + case execType == executorTypeExec: + // Non-internal queries are always logged to the slow query log. + p.logEventOnlyExternally(ctx, 0, /* log event not trigged by descriptor */ + &eventpb.SlowQuery{CommonSQLExecDetails: execDetails}) + + case execType == executorTypeInternal && slowInternalQueryLogEnabled: + // Internal queries that surpass the slow query log threshold should only + // be logged to the slow-internal-only log if the cluster setting dictates. + p.logEventOnlyExternally(ctx, 0, /* log event not trigged by descriptor */ + &eventpb.SlowQueryInternal{CommonSQLExecDetails: execDetails}) + } } - if logV { - // Copy to the debug log. - log.VEventf(ctx, execType.vLevel(), "%s %q %s %q %s %.3f %d %q %d", - lbl, appName, logTrigger, stmtStr, plStr, age, rows, execErrStr, numRetries) + + if logExecuteEnabled { + p.logEventOnlyExternally(ctx, 0, /* log event not trigged by descriptor */ + &eventpb.QueryExecute{CommonSQLExecDetails: execDetails}) } } diff --git a/pkg/util/log/eventpb/BUILD.bazel b/pkg/util/log/eventpb/BUILD.bazel index b2768d4bb791..14c2e29753aa 100644 --- a/pkg/util/log/eventpb/BUILD.bazel +++ b/pkg/util/log/eventpb/BUILD.bazel @@ -40,6 +40,7 @@ proto_library( "privilege_events.proto", "role_events.proto", "session_events.proto", + "sql_audit_events.proto", "zone_events.proto", ], strip_import_prefix = "/pkg", diff --git a/pkg/util/log/eventpb/eventlog_channels_generated.go b/pkg/util/log/eventpb/eventlog_channels_generated.go index 70e0cec265d7..76fb3587ae5d 100644 --- a/pkg/util/log/eventpb/eventlog_channels_generated.go +++ b/pkg/util/log/eventpb/eventlog_channels_generated.go @@ -22,6 +22,12 @@ func (m *NodeRestart) LoggingChannel() logpb.Channel { return logpb.Channel_OPS // LoggingChannel implements the EventPayload interface. func (m *SetClusterSetting) LoggingChannel() logpb.Channel { return logpb.Channel_DEV } +// LoggingChannel implements the EventPayload interface. +func (m *SensitiveTableAccess) LoggingChannel() logpb.Channel { return logpb.Channel_SENSITIVE_ACCESS } + +// LoggingChannel implements the EventPayload interface. +func (m *QueryExecute) LoggingChannel() logpb.Channel { return logpb.Channel_SQL_EXEC } + // LoggingChannel implements the EventPayload interface. func (m *AlterDatabaseAddRegion) LoggingChannel() logpb.Channel { return logpb.Channel_SQL_SCHEMA } @@ -181,6 +187,12 @@ func (m *ClientConnectionStart) LoggingChannel() logpb.Channel { return logpb.Ch // LoggingChannel implements the EventPayload interface. func (m *ClientSessionEnd) LoggingChannel() logpb.Channel { return logpb.Channel_SESSIONS } +// LoggingChannel implements the EventPayload interface. +func (m *SlowQuery) LoggingChannel() logpb.Channel { return logpb.Channel_SQL_PERF } + +// LoggingChannel implements the EventPayload interface. +func (m *SlowQueryInternal) LoggingChannel() logpb.Channel { return logpb.Channel_SQL_INTERNAL_PERF } + // LoggingChannel implements the EventPayload interface. func (m *AlterRole) LoggingChannel() logpb.Channel { return logpb.Channel_USER_ADMIN } diff --git a/pkg/util/log/eventpb/gen.go b/pkg/util/log/eventpb/gen.go index 522a6f823bc8..8d42f035997a 100644 --- a/pkg/util/log/eventpb/gen.go +++ b/pkg/util/log/eventpb/gen.go @@ -380,7 +380,7 @@ func readInput( func isSafeType(typ string) bool { switch typ { - case "timestamp", "int32", "int64", "int16", "uint32", "uint64", "uint16", "bool": + case "timestamp", "int32", "int64", "int16", "uint32", "uint64", "uint16", "bool", "float", "double": return true } return false @@ -483,6 +483,18 @@ func (m *{{.GoType}}) AppendJSONFields(printComma bool, b redact.RedactableBytes b = append(b, "\"{{.FieldName}}\":"...) b = strconv.AppendInt(b, int64(m.{{.FieldName}}), 10) } + {{- else if eq .FieldType "float"}} + if m.{{.FieldName}} != 0 { + if printComma { b = append(b, ',')}; printComma = true + b = append(b, "\"{{.FieldName}}\":"...) + b = strconv.AppendFloat(b, float64(m.{{.FieldName}}), 'f', -1, 32) + } + {{- else if eq .FieldType "double"}} + if m.{{.FieldName}} != 0 { + if printComma { b = append(b, ',')}; printComma = true + b = append(b, "\"{{.FieldName}}\":"...) + b = strconv.AppendFloat(b, float64(m.{{.FieldName}}), 'f', -1, 64) + } {{- else if eq .FieldType "uint16" "uint32" "uint64"}} if m.{{.FieldName}} != 0 { if printComma { b = append(b, ',')}; printComma = true diff --git a/pkg/util/log/eventpb/json_encode_generated.go b/pkg/util/log/eventpb/json_encode_generated.go index 17177988ccd2..f54bbd4c7d99 100644 --- a/pkg/util/log/eventpb/json_encode_generated.go +++ b/pkg/util/log/eventpb/json_encode_generated.go @@ -1049,6 +1049,87 @@ func (m *CommonSQLEventDetails) AppendJSONFields(printComma bool, b redact.Redac return printComma, b } +// AppendJSONFields implements the EventPayload interface. +func (m *CommonSQLExecDetails) AppendJSONFields(printComma bool, b redact.RedactableBytes) (bool, redact.RedactableBytes) { + + if m.ExecMode != "" { + if printComma { + b = append(b, ',') + } + printComma = true + b = append(b, "\"ExecMode\":\""...) + b = redact.RedactableBytes(jsonbytes.EncodeString([]byte(b), m.ExecMode)) + b = append(b, '"') + } + + if m.NumRows != 0 { + if printComma { + b = append(b, ',') + } + printComma = true + b = append(b, "\"NumRows\":"...) + b = strconv.AppendUint(b, uint64(m.NumRows), 10) + } + + if m.SQLSTATE != "" { + if printComma { + b = append(b, ',') + } + printComma = true + b = append(b, "\"SQLSTATE\":\""...) + b = redact.RedactableBytes(jsonbytes.EncodeString([]byte(b), m.SQLSTATE)) + b = append(b, '"') + } + + if m.ErrorText != "" { + if printComma { + b = append(b, ',') + } + printComma = true + b = append(b, "\"ErrorText\":\""...) + b = append(b, redact.StartMarker()...) + b = redact.RedactableBytes(jsonbytes.EncodeString([]byte(b), string(redact.EscapeMarkers([]byte(m.ErrorText))))) + b = append(b, redact.EndMarker()...) + b = append(b, '"') + } + + if m.Age != 0 { + if printComma { + b = append(b, ',') + } + printComma = true + b = append(b, "\"Age\":"...) + b = strconv.AppendFloat(b, float64(m.Age), 'f', -1, 32) + } + + if m.NumRetries != 0 { + if printComma { + b = append(b, ',') + } + printComma = true + b = append(b, "\"NumRetries\":"...) + b = strconv.AppendUint(b, uint64(m.NumRetries), 10) + } + + if m.FullTableScan { + if printComma { + b = append(b, ',') + } + printComma = true + b = append(b, "\"FullTableScan\":true"...) + } + + if m.FullIndexScan { + if printComma { + b = append(b, ',') + } + printComma = true + b = append(b, "\"FullIndexScan\":true"...) + } + + return printComma, b +} + // AppendJSONFields implements the EventPayload interface. func (m *CommonSQLPrivilegeEventDetails) AppendJSONFields(printComma bool, b redact.RedactableBytes) (bool, redact.RedactableBytes) { @@ -1879,6 +1960,18 @@ func (m *NodeRestart) AppendJSONFields(printComma bool, b redact.RedactableBytes return printComma, b } +// AppendJSONFields implements the EventPayload interface. +func (m *QueryExecute) AppendJSONFields(printComma bool, b redact.RedactableBytes) (bool, redact.RedactableBytes) { + + printComma, b = m.CommonEventDetails.AppendJSONFields(printComma, b) + + printComma, b = m.CommonSQLEventDetails.AppendJSONFields(printComma, b) + + printComma, b = m.CommonSQLExecDetails.AppendJSONFields(printComma, b) + + return printComma, b +} + // AppendJSONFields implements the EventPayload interface. func (m *RemoveZoneConfig) AppendJSONFields(printComma bool, b redact.RedactableBytes) (bool, redact.RedactableBytes) { @@ -2059,6 +2152,40 @@ func (m *ReverseSchemaChange) AppendJSONFields(printComma bool, b redact.Redacta return printComma, b } +// AppendJSONFields implements the EventPayload interface. +func (m *SensitiveTableAccess) AppendJSONFields(printComma bool, b redact.RedactableBytes) (bool, redact.RedactableBytes) { + + printComma, b = m.CommonEventDetails.AppendJSONFields(printComma, b) + + printComma, b = m.CommonSQLEventDetails.AppendJSONFields(printComma, b) + + printComma, b = m.CommonSQLExecDetails.AppendJSONFields(printComma, b) + + if m.TableName != "" { + if printComma { + b = append(b, ',') + } + printComma = true + b = append(b, "\"TableName\":\""...) + b = append(b, redact.StartMarker()...) + b = redact.RedactableBytes(jsonbytes.EncodeString([]byte(b), string(redact.EscapeMarkers([]byte(m.TableName))))) + b = append(b, redact.EndMarker()...) + b = append(b, '"') + } + + if m.AccessMode != "" { + if printComma { + b = append(b, ',') + } + printComma = true + b = append(b, "\"AccessMode\":\""...) + b = redact.RedactableBytes(jsonbytes.EncodeString([]byte(b), m.AccessMode)) + b = append(b, '"') + } + + return printComma, b +} + // AppendJSONFields implements the EventPayload interface. func (m *SetClusterSetting) AppendJSONFields(printComma bool, b redact.RedactableBytes) (bool, redact.RedactableBytes) { @@ -2103,6 +2230,30 @@ func (m *SetZoneConfig) AppendJSONFields(printComma bool, b redact.RedactableByt return printComma, b } +// AppendJSONFields implements the EventPayload interface. +func (m *SlowQuery) AppendJSONFields(printComma bool, b redact.RedactableBytes) (bool, redact.RedactableBytes) { + + printComma, b = m.CommonEventDetails.AppendJSONFields(printComma, b) + + printComma, b = m.CommonSQLEventDetails.AppendJSONFields(printComma, b) + + printComma, b = m.CommonSQLExecDetails.AppendJSONFields(printComma, b) + + return printComma, b +} + +// AppendJSONFields implements the EventPayload interface. +func (m *SlowQueryInternal) AppendJSONFields(printComma bool, b redact.RedactableBytes) (bool, redact.RedactableBytes) { + + printComma, b = m.CommonEventDetails.AppendJSONFields(printComma, b) + + printComma, b = m.CommonSQLEventDetails.AppendJSONFields(printComma, b) + + printComma, b = m.CommonSQLExecDetails.AppendJSONFields(printComma, b) + + return printComma, b +} + // AppendJSONFields implements the EventPayload interface. func (m *TruncateTable) AppendJSONFields(printComma bool, b redact.RedactableBytes) (bool, redact.RedactableBytes) { diff --git a/pkg/util/log/eventpb/sql_audit_events.pb.go b/pkg/util/log/eventpb/sql_audit_events.pb.go new file mode 100644 index 000000000000..1683d32e7ba5 --- /dev/null +++ b/pkg/util/log/eventpb/sql_audit_events.pb.go @@ -0,0 +1,1613 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: util/log/eventpb/sql_audit_events.proto + +package eventpb + +import proto "github.com/gogo/protobuf/proto" +import fmt "fmt" +import math "math" + +import encoding_binary "encoding/binary" + +import io "io" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package + +// CommonSQLExecDetails contains the field common to all SQL query logs. +type CommonSQLExecDetails struct { + // How the statement was being executed (exec/prepare, etc.) + ExecMode string `protobuf:"bytes,1,opt,name=exec_mode,json=execMode,proto3" json:",omitempty" redact:"nonsensitive"` + // Number of rows returned. For mutation statements (INSERT, etc) that + // do not produce result rows, this field reports the number of rows affected. + NumRows uint64 `protobuf:"varint,2,opt,name=num_rows,json=numRows,proto3" json:",omitempty"` + // The SQLSTATE code for the error, if an error was encountered. Empty/omitted if no error. + SQLSTATE string `protobuf:"bytes,3,opt,name=sqlstate,proto3" json:",omitempty" redact:"nonsensitive"` + // The text of the error if any. + ErrorText string `protobuf:"bytes,4,opt,name=error_text,json=errorText,proto3" json:",omitempty"` + // Age of the query in milliseconds. + Age float32 `protobuf:"fixed32,5,opt,name=age,proto3" json:",omitempty"` + // Number of retries, when the txn was reretried automatically by the server. + NumRetries uint32 `protobuf:"varint,6,opt,name=num_retries,json=numRetries,proto3" json:",omitempty"` + // Whether the query contains a full table scan. + FullTableScan bool `protobuf:"varint,7,opt,name=full_table_scan,json=fullTableScan,proto3" json:",omitempty"` + // Whether the query contains a full secondary index scan. + FullIndexScan bool `protobuf:"varint,8,opt,name=full_index_scan,json=fullIndexScan,proto3" json:",omitempty"` +} + +func (m *CommonSQLExecDetails) Reset() { *m = CommonSQLExecDetails{} } +func (m *CommonSQLExecDetails) String() string { return proto.CompactTextString(m) } +func (*CommonSQLExecDetails) ProtoMessage() {} +func (*CommonSQLExecDetails) Descriptor() ([]byte, []int) { + return fileDescriptor_sql_audit_events_814888d4efe7ce76, []int{0} +} +func (m *CommonSQLExecDetails) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CommonSQLExecDetails) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (dst *CommonSQLExecDetails) XXX_Merge(src proto.Message) { + xxx_messageInfo_CommonSQLExecDetails.Merge(dst, src) +} +func (m *CommonSQLExecDetails) XXX_Size() int { + return m.Size() +} +func (m *CommonSQLExecDetails) XXX_DiscardUnknown() { + xxx_messageInfo_CommonSQLExecDetails.DiscardUnknown(m) +} + +var xxx_messageInfo_CommonSQLExecDetails proto.InternalMessageInfo + +// SensitiveTableAccess is recorded when an access is performed to +// a table marked as audited. +type SensitiveTableAccess struct { + CommonEventDetails `protobuf:"bytes,1,opt,name=common,proto3,embedded=common" json:""` + CommonSQLEventDetails `protobuf:"bytes,2,opt,name=sql,proto3,embedded=sql" json:""` + CommonSQLExecDetails `protobuf:"bytes,3,opt,name=exec,proto3,embedded=exec" json:""` + // The name of the table being audited. + TableName string `protobuf:"bytes,4,opt,name=table_name,json=tableName,proto3" json:",omitempty"` + // How the table was accessed (r=read / rw=read/write). + AccessMode string `protobuf:"bytes,5,opt,name=access_mode,json=accessMode,proto3" json:",omitempty" redact:"nonsensitive"` +} + +func (m *SensitiveTableAccess) Reset() { *m = SensitiveTableAccess{} } +func (m *SensitiveTableAccess) String() string { return proto.CompactTextString(m) } +func (*SensitiveTableAccess) ProtoMessage() {} +func (*SensitiveTableAccess) Descriptor() ([]byte, []int) { + return fileDescriptor_sql_audit_events_814888d4efe7ce76, []int{1} +} +func (m *SensitiveTableAccess) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SensitiveTableAccess) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (dst *SensitiveTableAccess) XXX_Merge(src proto.Message) { + xxx_messageInfo_SensitiveTableAccess.Merge(dst, src) +} +func (m *SensitiveTableAccess) XXX_Size() int { + return m.Size() +} +func (m *SensitiveTableAccess) XXX_DiscardUnknown() { + xxx_messageInfo_SensitiveTableAccess.DiscardUnknown(m) +} + +var xxx_messageInfo_SensitiveTableAccess proto.InternalMessageInfo + +// SlowQuery is recorded when a query triggers the "slow query" condition. +// +// As of this writing, the condition requires: +// - the cluster setting `sql.log.slow_query.latency_threshold` +// set to a non-zero value, AND +// - EITHER of the following conditions: +// - the actual age of the query exceeds the configured threshold; OR +// - the query performs a full table/index scan. +type SlowQuery struct { + CommonEventDetails `protobuf:"bytes,1,opt,name=common,proto3,embedded=common" json:""` + CommonSQLEventDetails `protobuf:"bytes,2,opt,name=sql,proto3,embedded=sql" json:""` + CommonSQLExecDetails `protobuf:"bytes,3,opt,name=exec,proto3,embedded=exec" json:""` +} + +func (m *SlowQuery) Reset() { *m = SlowQuery{} } +func (m *SlowQuery) String() string { return proto.CompactTextString(m) } +func (*SlowQuery) ProtoMessage() {} +func (*SlowQuery) Descriptor() ([]byte, []int) { + return fileDescriptor_sql_audit_events_814888d4efe7ce76, []int{2} +} +func (m *SlowQuery) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SlowQuery) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (dst *SlowQuery) XXX_Merge(src proto.Message) { + xxx_messageInfo_SlowQuery.Merge(dst, src) +} +func (m *SlowQuery) XXX_Size() int { + return m.Size() +} +func (m *SlowQuery) XXX_DiscardUnknown() { + xxx_messageInfo_SlowQuery.DiscardUnknown(m) +} + +var xxx_messageInfo_SlowQuery proto.InternalMessageInfo + +// SlowQueryInternal is recorded when a query triggers the "slow query" condition, +// and the cluster setting `sql.log.slow_query.internal_queries.enabled` is +// set. +// See the documentation for the event type `slow_query` for details about +// the "slow query" condition. +type SlowQueryInternal struct { + CommonEventDetails `protobuf:"bytes,1,opt,name=common,proto3,embedded=common" json:""` + CommonSQLEventDetails `protobuf:"bytes,2,opt,name=sql,proto3,embedded=sql" json:""` + CommonSQLExecDetails `protobuf:"bytes,3,opt,name=exec,proto3,embedded=exec" json:""` +} + +func (m *SlowQueryInternal) Reset() { *m = SlowQueryInternal{} } +func (m *SlowQueryInternal) String() string { return proto.CompactTextString(m) } +func (*SlowQueryInternal) ProtoMessage() {} +func (*SlowQueryInternal) Descriptor() ([]byte, []int) { + return fileDescriptor_sql_audit_events_814888d4efe7ce76, []int{3} +} +func (m *SlowQueryInternal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SlowQueryInternal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (dst *SlowQueryInternal) XXX_Merge(src proto.Message) { + xxx_messageInfo_SlowQueryInternal.Merge(dst, src) +} +func (m *SlowQueryInternal) XXX_Size() int { + return m.Size() +} +func (m *SlowQueryInternal) XXX_DiscardUnknown() { + xxx_messageInfo_SlowQueryInternal.DiscardUnknown(m) +} + +var xxx_messageInfo_SlowQueryInternal proto.InternalMessageInfo + +// QueryExecute is recorded when a query is executed, +// and the cluster setting `sql.trace.log_statement_execute` is set. +type QueryExecute struct { + CommonEventDetails `protobuf:"bytes,1,opt,name=common,proto3,embedded=common" json:""` + CommonSQLEventDetails `protobuf:"bytes,2,opt,name=sql,proto3,embedded=sql" json:""` + CommonSQLExecDetails `protobuf:"bytes,3,opt,name=exec,proto3,embedded=exec" json:""` +} + +func (m *QueryExecute) Reset() { *m = QueryExecute{} } +func (m *QueryExecute) String() string { return proto.CompactTextString(m) } +func (*QueryExecute) ProtoMessage() {} +func (*QueryExecute) Descriptor() ([]byte, []int) { + return fileDescriptor_sql_audit_events_814888d4efe7ce76, []int{4} +} +func (m *QueryExecute) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryExecute) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (dst *QueryExecute) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryExecute.Merge(dst, src) +} +func (m *QueryExecute) XXX_Size() int { + return m.Size() +} +func (m *QueryExecute) XXX_DiscardUnknown() { + xxx_messageInfo_QueryExecute.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryExecute proto.InternalMessageInfo + +func init() { + proto.RegisterType((*CommonSQLExecDetails)(nil), "cockroach.util.log.eventpb.CommonSQLExecDetails") + proto.RegisterType((*SensitiveTableAccess)(nil), "cockroach.util.log.eventpb.SensitiveTableAccess") + proto.RegisterType((*SlowQuery)(nil), "cockroach.util.log.eventpb.SlowQuery") + proto.RegisterType((*SlowQueryInternal)(nil), "cockroach.util.log.eventpb.SlowQueryInternal") + proto.RegisterType((*QueryExecute)(nil), "cockroach.util.log.eventpb.QueryExecute") +} +func (m *CommonSQLExecDetails) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *CommonSQLExecDetails) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.ExecMode) > 0 { + dAtA[i] = 0xa + i++ + i = encodeVarintSqlAuditEvents(dAtA, i, uint64(len(m.ExecMode))) + i += copy(dAtA[i:], m.ExecMode) + } + if m.NumRows != 0 { + dAtA[i] = 0x10 + i++ + i = encodeVarintSqlAuditEvents(dAtA, i, uint64(m.NumRows)) + } + if len(m.SQLSTATE) > 0 { + dAtA[i] = 0x1a + i++ + i = encodeVarintSqlAuditEvents(dAtA, i, uint64(len(m.SQLSTATE))) + i += copy(dAtA[i:], m.SQLSTATE) + } + if len(m.ErrorText) > 0 { + dAtA[i] = 0x22 + i++ + i = encodeVarintSqlAuditEvents(dAtA, i, uint64(len(m.ErrorText))) + i += copy(dAtA[i:], m.ErrorText) + } + if m.Age != 0 { + dAtA[i] = 0x2d + i++ + encoding_binary.LittleEndian.PutUint32(dAtA[i:], uint32(math.Float32bits(float32(m.Age)))) + i += 4 + } + if m.NumRetries != 0 { + dAtA[i] = 0x30 + i++ + i = encodeVarintSqlAuditEvents(dAtA, i, uint64(m.NumRetries)) + } + if m.FullTableScan { + dAtA[i] = 0x38 + i++ + if m.FullTableScan { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i++ + } + if m.FullIndexScan { + dAtA[i] = 0x40 + i++ + if m.FullIndexScan { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i++ + } + return i, nil +} + +func (m *SensitiveTableAccess) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *SensitiveTableAccess) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + dAtA[i] = 0xa + i++ + i = encodeVarintSqlAuditEvents(dAtA, i, uint64(m.CommonEventDetails.Size())) + n1, err := m.CommonEventDetails.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n1 + dAtA[i] = 0x12 + i++ + i = encodeVarintSqlAuditEvents(dAtA, i, uint64(m.CommonSQLEventDetails.Size())) + n2, err := m.CommonSQLEventDetails.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n2 + dAtA[i] = 0x1a + i++ + i = encodeVarintSqlAuditEvents(dAtA, i, uint64(m.CommonSQLExecDetails.Size())) + n3, err := m.CommonSQLExecDetails.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n3 + if len(m.TableName) > 0 { + dAtA[i] = 0x22 + i++ + i = encodeVarintSqlAuditEvents(dAtA, i, uint64(len(m.TableName))) + i += copy(dAtA[i:], m.TableName) + } + if len(m.AccessMode) > 0 { + dAtA[i] = 0x2a + i++ + i = encodeVarintSqlAuditEvents(dAtA, i, uint64(len(m.AccessMode))) + i += copy(dAtA[i:], m.AccessMode) + } + return i, nil +} + +func (m *SlowQuery) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *SlowQuery) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + dAtA[i] = 0xa + i++ + i = encodeVarintSqlAuditEvents(dAtA, i, uint64(m.CommonEventDetails.Size())) + n4, err := m.CommonEventDetails.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n4 + dAtA[i] = 0x12 + i++ + i = encodeVarintSqlAuditEvents(dAtA, i, uint64(m.CommonSQLEventDetails.Size())) + n5, err := m.CommonSQLEventDetails.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n5 + dAtA[i] = 0x1a + i++ + i = encodeVarintSqlAuditEvents(dAtA, i, uint64(m.CommonSQLExecDetails.Size())) + n6, err := m.CommonSQLExecDetails.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n6 + return i, nil +} + +func (m *SlowQueryInternal) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *SlowQueryInternal) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + dAtA[i] = 0xa + i++ + i = encodeVarintSqlAuditEvents(dAtA, i, uint64(m.CommonEventDetails.Size())) + n7, err := m.CommonEventDetails.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n7 + dAtA[i] = 0x12 + i++ + i = encodeVarintSqlAuditEvents(dAtA, i, uint64(m.CommonSQLEventDetails.Size())) + n8, err := m.CommonSQLEventDetails.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n8 + dAtA[i] = 0x1a + i++ + i = encodeVarintSqlAuditEvents(dAtA, i, uint64(m.CommonSQLExecDetails.Size())) + n9, err := m.CommonSQLExecDetails.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n9 + return i, nil +} + +func (m *QueryExecute) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryExecute) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + dAtA[i] = 0xa + i++ + i = encodeVarintSqlAuditEvents(dAtA, i, uint64(m.CommonEventDetails.Size())) + n10, err := m.CommonEventDetails.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n10 + dAtA[i] = 0x12 + i++ + i = encodeVarintSqlAuditEvents(dAtA, i, uint64(m.CommonSQLEventDetails.Size())) + n11, err := m.CommonSQLEventDetails.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n11 + dAtA[i] = 0x1a + i++ + i = encodeVarintSqlAuditEvents(dAtA, i, uint64(m.CommonSQLExecDetails.Size())) + n12, err := m.CommonSQLExecDetails.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n12 + return i, nil +} + +func encodeVarintSqlAuditEvents(dAtA []byte, offset int, v uint64) int { + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return offset + 1 +} +func (m *CommonSQLExecDetails) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ExecMode) + if l > 0 { + n += 1 + l + sovSqlAuditEvents(uint64(l)) + } + if m.NumRows != 0 { + n += 1 + sovSqlAuditEvents(uint64(m.NumRows)) + } + l = len(m.SQLSTATE) + if l > 0 { + n += 1 + l + sovSqlAuditEvents(uint64(l)) + } + l = len(m.ErrorText) + if l > 0 { + n += 1 + l + sovSqlAuditEvents(uint64(l)) + } + if m.Age != 0 { + n += 5 + } + if m.NumRetries != 0 { + n += 1 + sovSqlAuditEvents(uint64(m.NumRetries)) + } + if m.FullTableScan { + n += 2 + } + if m.FullIndexScan { + n += 2 + } + return n +} + +func (m *SensitiveTableAccess) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.CommonEventDetails.Size() + n += 1 + l + sovSqlAuditEvents(uint64(l)) + l = m.CommonSQLEventDetails.Size() + n += 1 + l + sovSqlAuditEvents(uint64(l)) + l = m.CommonSQLExecDetails.Size() + n += 1 + l + sovSqlAuditEvents(uint64(l)) + l = len(m.TableName) + if l > 0 { + n += 1 + l + sovSqlAuditEvents(uint64(l)) + } + l = len(m.AccessMode) + if l > 0 { + n += 1 + l + sovSqlAuditEvents(uint64(l)) + } + return n +} + +func (m *SlowQuery) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.CommonEventDetails.Size() + n += 1 + l + sovSqlAuditEvents(uint64(l)) + l = m.CommonSQLEventDetails.Size() + n += 1 + l + sovSqlAuditEvents(uint64(l)) + l = m.CommonSQLExecDetails.Size() + n += 1 + l + sovSqlAuditEvents(uint64(l)) + return n +} + +func (m *SlowQueryInternal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.CommonEventDetails.Size() + n += 1 + l + sovSqlAuditEvents(uint64(l)) + l = m.CommonSQLEventDetails.Size() + n += 1 + l + sovSqlAuditEvents(uint64(l)) + l = m.CommonSQLExecDetails.Size() + n += 1 + l + sovSqlAuditEvents(uint64(l)) + return n +} + +func (m *QueryExecute) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.CommonEventDetails.Size() + n += 1 + l + sovSqlAuditEvents(uint64(l)) + l = m.CommonSQLEventDetails.Size() + n += 1 + l + sovSqlAuditEvents(uint64(l)) + l = m.CommonSQLExecDetails.Size() + n += 1 + l + sovSqlAuditEvents(uint64(l)) + return n +} + +func sovSqlAuditEvents(x uint64) (n int) { + for { + n++ + x >>= 7 + if x == 0 { + break + } + } + return n +} +func sozSqlAuditEvents(x uint64) (n int) { + return sovSqlAuditEvents(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *CommonSQLExecDetails) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSqlAuditEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: CommonSQLExecDetails: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CommonSQLExecDetails: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ExecMode", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSqlAuditEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSqlAuditEvents + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ExecMode = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NumRows", wireType) + } + m.NumRows = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSqlAuditEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.NumRows |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SQLSTATE", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSqlAuditEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSqlAuditEvents + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SQLSTATE = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ErrorText", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSqlAuditEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSqlAuditEvents + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ErrorText = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 5 { + return fmt.Errorf("proto: wrong wireType = %d for field Age", wireType) + } + var v uint32 + if (iNdEx + 4) > l { + return io.ErrUnexpectedEOF + } + v = uint32(encoding_binary.LittleEndian.Uint32(dAtA[iNdEx:])) + iNdEx += 4 + m.Age = float32(math.Float32frombits(v)) + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NumRetries", wireType) + } + m.NumRetries = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSqlAuditEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.NumRetries |= (uint32(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field FullTableScan", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSqlAuditEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + m.FullTableScan = bool(v != 0) + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field FullIndexScan", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSqlAuditEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + m.FullIndexScan = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipSqlAuditEvents(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthSqlAuditEvents + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *SensitiveTableAccess) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSqlAuditEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: SensitiveTableAccess: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SensitiveTableAccess: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CommonEventDetails", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSqlAuditEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSqlAuditEvents + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.CommonEventDetails.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CommonSQLEventDetails", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSqlAuditEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSqlAuditEvents + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.CommonSQLEventDetails.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CommonSQLExecDetails", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSqlAuditEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSqlAuditEvents + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.CommonSQLExecDetails.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TableName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSqlAuditEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSqlAuditEvents + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TableName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AccessMode", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSqlAuditEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSqlAuditEvents + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AccessMode = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipSqlAuditEvents(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthSqlAuditEvents + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *SlowQuery) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSqlAuditEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: SlowQuery: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SlowQuery: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CommonEventDetails", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSqlAuditEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSqlAuditEvents + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.CommonEventDetails.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CommonSQLEventDetails", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSqlAuditEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSqlAuditEvents + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.CommonSQLEventDetails.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CommonSQLExecDetails", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSqlAuditEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSqlAuditEvents + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.CommonSQLExecDetails.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipSqlAuditEvents(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthSqlAuditEvents + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *SlowQueryInternal) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSqlAuditEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: SlowQueryInternal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SlowQueryInternal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CommonEventDetails", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSqlAuditEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSqlAuditEvents + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.CommonEventDetails.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CommonSQLEventDetails", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSqlAuditEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSqlAuditEvents + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.CommonSQLEventDetails.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CommonSQLExecDetails", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSqlAuditEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSqlAuditEvents + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.CommonSQLExecDetails.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipSqlAuditEvents(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthSqlAuditEvents + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryExecute) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSqlAuditEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryExecute: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryExecute: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CommonEventDetails", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSqlAuditEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSqlAuditEvents + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.CommonEventDetails.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CommonSQLEventDetails", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSqlAuditEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSqlAuditEvents + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.CommonSQLEventDetails.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CommonSQLExecDetails", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSqlAuditEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSqlAuditEvents + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.CommonSQLExecDetails.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipSqlAuditEvents(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthSqlAuditEvents + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipSqlAuditEvents(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowSqlAuditEvents + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowSqlAuditEvents + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + return iNdEx, nil + case 1: + iNdEx += 8 + return iNdEx, nil + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowSqlAuditEvents + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + iNdEx += length + if length < 0 { + return 0, ErrInvalidLengthSqlAuditEvents + } + return iNdEx, nil + case 3: + for { + var innerWire uint64 + var start int = iNdEx + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowSqlAuditEvents + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + innerWire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + innerWireType := int(innerWire & 0x7) + if innerWireType == 4 { + break + } + next, err := skipSqlAuditEvents(dAtA[start:]) + if err != nil { + return 0, err + } + iNdEx = start + next + } + return iNdEx, nil + case 4: + return iNdEx, nil + case 5: + iNdEx += 4 + return iNdEx, nil + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + } + panic("unreachable") +} + +var ( + ErrInvalidLengthSqlAuditEvents = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowSqlAuditEvents = fmt.Errorf("proto: integer overflow") +) + +func init() { + proto.RegisterFile("util/log/eventpb/sql_audit_events.proto", fileDescriptor_sql_audit_events_814888d4efe7ce76) +} + +var fileDescriptor_sql_audit_events_814888d4efe7ce76 = []byte{ + // 581 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x95, 0x3f, 0x6f, 0xd3, 0x4e, + 0x18, 0xc7, 0xed, 0xa4, 0x7f, 0x9c, 0x4b, 0xfb, 0xfb, 0x89, 0x53, 0x91, 0xac, 0x4a, 0xd8, 0x96, + 0x97, 0xa6, 0x12, 0x38, 0xd0, 0x4a, 0x0c, 0x6c, 0x0d, 0xad, 0x44, 0xa5, 0x02, 0x4a, 0x9c, 0x89, + 0xc5, 0xba, 0x3a, 0x0f, 0xc1, 0xe2, 0x7c, 0xd7, 0xfa, 0xce, 0x6d, 0xfa, 0x0e, 0x90, 0x60, 0xe8, + 0xcb, 0x8a, 0x98, 0x32, 0x76, 0xb2, 0x20, 0xd9, 0x3a, 0xf2, 0x0a, 0xd0, 0x9d, 0xd3, 0x02, 0x8d, + 0x22, 0xca, 0x9c, 0x2d, 0xb1, 0xbf, 0xdf, 0xcf, 0xe9, 0x9e, 0xe7, 0x23, 0x19, 0x6d, 0xe5, 0x32, + 0xa1, 0x4d, 0xca, 0xfb, 0x4d, 0x38, 0x03, 0x26, 0x4f, 0x8e, 0x9b, 0xe2, 0x94, 0x46, 0x24, 0xef, + 0x25, 0x32, 0xd2, 0x4f, 0x44, 0x70, 0x92, 0x71, 0xc9, 0xf1, 0x66, 0xcc, 0xe3, 0x8f, 0x19, 0x27, + 0xf1, 0x87, 0x40, 0x55, 0x02, 0xca, 0xfb, 0xc1, 0xb4, 0xb2, 0xb9, 0xd1, 0xe7, 0x7d, 0xae, 0x63, + 0x4d, 0xf5, 0xab, 0x6c, 0x6c, 0x3e, 0x9a, 0x41, 0xff, 0x0e, 0xf4, 0xbf, 0x56, 0xd1, 0xc6, 0x4b, + 0x9e, 0xa6, 0x9c, 0x85, 0xed, 0xa3, 0x83, 0x01, 0xc4, 0xfb, 0x20, 0x49, 0x42, 0x05, 0xde, 0x47, + 0x35, 0x18, 0x40, 0x1c, 0xa5, 0xbc, 0x07, 0xb6, 0xe9, 0x99, 0x8d, 0x5a, 0x6b, 0xeb, 0xba, 0x70, + 0xd1, 0x63, 0x9e, 0x26, 0x12, 0xd2, 0x13, 0x79, 0xf1, 0xa3, 0x70, 0x1f, 0x66, 0xd0, 0x23, 0xb1, + 0x7c, 0xe1, 0x33, 0xce, 0x04, 0x30, 0x91, 0xc8, 0xe4, 0x0c, 0xfc, 0x8e, 0xa5, 0x9a, 0xaf, 0x79, + 0x0f, 0xf0, 0x36, 0xb2, 0x58, 0x9e, 0x46, 0x19, 0x3f, 0x17, 0x76, 0xc5, 0x33, 0x1b, 0x4b, 0xad, + 0xff, 0xfe, 0x84, 0x74, 0x56, 0x59, 0x9e, 0x76, 0xf8, 0xb9, 0xc0, 0x6f, 0x91, 0x25, 0x4e, 0xa9, + 0x90, 0x44, 0x82, 0x5d, 0xd5, 0xe7, 0xed, 0x8e, 0x0b, 0xd7, 0x0a, 0xdb, 0x47, 0x61, 0x77, 0xaf, + 0x7b, 0x70, 0xef, 0xb3, 0x6f, 0x20, 0xf8, 0x09, 0x42, 0x90, 0x65, 0x3c, 0x8b, 0x24, 0x0c, 0xa4, + 0xbd, 0xa4, 0x91, 0x77, 0x4f, 0xaf, 0xe9, 0x44, 0x17, 0x06, 0x12, 0x7b, 0xa8, 0x4a, 0xfa, 0x60, + 0x2f, 0x7b, 0x66, 0xa3, 0x32, 0x93, 0x53, 0xaf, 0x70, 0x13, 0xd5, 0xf5, 0x65, 0x40, 0x66, 0x09, + 0x08, 0x7b, 0xc5, 0x33, 0x1b, 0xeb, 0x33, 0x49, 0xa4, 0xee, 0x53, 0x26, 0xf0, 0x73, 0xf4, 0xff, + 0xfb, 0x9c, 0xd2, 0x48, 0x92, 0x63, 0x0a, 0x91, 0x88, 0x09, 0xb3, 0x57, 0x3d, 0xb3, 0x61, 0xcd, + 0x94, 0xd6, 0x55, 0xac, 0xab, 0x52, 0x61, 0x4c, 0xd8, 0x6d, 0x2f, 0x61, 0x3d, 0x18, 0x94, 0x3d, + 0x6b, 0x7e, 0xef, 0x50, 0xa5, 0x54, 0xcf, 0xff, 0x52, 0x45, 0x1b, 0xe1, 0xcd, 0x28, 0x34, 0x6e, + 0x2f, 0x8e, 0x41, 0x08, 0xdc, 0x45, 0x2b, 0xb1, 0x5e, 0xb2, 0xde, 0x64, 0x7d, 0x27, 0x08, 0xe6, + 0x7b, 0x14, 0x94, 0x3a, 0x1c, 0xa8, 0x7f, 0x53, 0x19, 0x5a, 0x6b, 0xc3, 0xc2, 0x35, 0x46, 0x85, + 0x6b, 0x5e, 0x17, 0xae, 0xd1, 0x99, 0xb2, 0x70, 0x1b, 0x55, 0xc5, 0x29, 0xd5, 0x7b, 0xad, 0xef, + 0x3c, 0xfb, 0x3b, 0x52, 0x19, 0x36, 0x9f, 0xaa, 0x58, 0xb8, 0x83, 0x96, 0x94, 0x3b, 0x5a, 0x80, + 0xfa, 0xce, 0xd3, 0xfb, 0x31, 0x7f, 0x59, 0x7b, 0x07, 0xa9, 0x59, 0xca, 0x83, 0x72, 0x01, 0x8c, + 0xa4, 0x30, 0xcf, 0x03, 0x9d, 0x78, 0x43, 0x52, 0xc0, 0xaf, 0x50, 0x9d, 0xe8, 0xa9, 0x95, 0xea, + 0x2f, 0xff, 0x9b, 0xfa, 0xa8, 0xec, 0x2a, 0xf9, 0xfd, 0x4f, 0x15, 0x54, 0x0b, 0x29, 0x3f, 0x6f, + 0xe7, 0x90, 0x5d, 0x2c, 0xf4, 0x0e, 0xfc, 0xcb, 0x0a, 0x7a, 0x70, 0x3b, 0x8a, 0x43, 0x26, 0x21, + 0x63, 0x84, 0x2e, 0xf6, 0x48, 0x3e, 0x57, 0xd0, 0x9a, 0x1e, 0x87, 0x0a, 0xe6, 0x12, 0x16, 0x7a, + 0x1a, 0xad, 0xed, 0xe1, 0x77, 0xc7, 0x18, 0x8e, 0x1d, 0x73, 0x34, 0x76, 0xcc, 0xab, 0xb1, 0x63, + 0x7e, 0x1b, 0x3b, 0xe6, 0xe5, 0xc4, 0x31, 0x46, 0x13, 0xc7, 0xb8, 0x9a, 0x38, 0xc6, 0xbb, 0xd5, + 0x29, 0xf3, 0x78, 0x45, 0x7f, 0xb9, 0x76, 0x7f, 0x06, 0x00, 0x00, 0xff, 0xff, 0x86, 0x4c, 0x26, + 0x8b, 0x35, 0x07, 0x00, 0x00, +} diff --git a/pkg/util/log/eventpb/sql_audit_events.proto b/pkg/util/log/eventpb/sql_audit_events.proto new file mode 100644 index 000000000000..c88818226c78 --- /dev/null +++ b/pkg/util/log/eventpb/sql_audit_events.proto @@ -0,0 +1,131 @@ +// Copyright 2020 The Cockroach Authors. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +syntax = "proto3"; +package cockroach.util.log.eventpb; +option go_package = "eventpb"; + +import "gogoproto/gogo.proto"; +import "util/log/eventpb/events.proto"; + +// Notes to CockroachDB maintainers: refer to doc.go at the package +// level for more details. Beware that JSON compatibility rules apply +// here, not protobuf. +// *Really look at doc.go before modifying this file.* + +// CommonSQLExecDetails contains the field common to all SQL query logs. +message CommonSQLExecDetails { + // How the statement was being executed (exec/prepare, etc.) + string exec_mode = 1 [(gogoproto.jsontag) = ",omitempty", (gogoproto.moretags) = "redact:\"nonsensitive\""]; + // Number of rows returned. For mutation statements (INSERT, etc) that + // do not produce result rows, this field reports the number of rows affected. + uint64 num_rows = 2 [(gogoproto.jsontag) = ",omitempty"]; + // The SQLSTATE code for the error, if an error was encountered. Empty/omitted if no error. + string sqlstate = 3 [(gogoproto.customname) = "SQLSTATE", (gogoproto.jsontag) = ",omitempty", (gogoproto.moretags) = "redact:\"nonsensitive\""]; + // The text of the error if any. + string error_text = 4 [(gogoproto.jsontag) = ",omitempty"]; + // Age of the query in milliseconds. + float age = 5 [(gogoproto.jsontag) = ",omitempty"]; + // Number of retries, when the txn was reretried automatically by the server. + uint32 num_retries = 6 [(gogoproto.jsontag) = ",omitempty"]; + // Whether the query contains a full table scan. + bool full_table_scan = 7 [(gogoproto.jsontag) = ",omitempty"]; + // Whether the query contains a full secondary index scan. + bool full_index_scan = 8 [(gogoproto.jsontag) = ",omitempty"]; +} + + +// Category: SQL Access Audit Events +// Channel: SENSITIVE_ACCESS +// +// Events in this category are generated when a table has been +// marked as audited via `ALTER ... EXPERIMENTAL_AUDIT SET`. +// +// This feature is experimental. +// +// Note: these events are not written to `system.eventlog`, even +// when the cluster setting `system.eventlog.enabled` is set. They +// are only emitted via external logging. + +// SensitiveTableAccess is recorded when an access is performed to +// a table marked as audited. +message SensitiveTableAccess { + CommonEventDetails common = 1 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "", (gogoproto.embed) = true]; + CommonSQLEventDetails sql = 2 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "", (gogoproto.embed) = true]; + CommonSQLExecDetails exec = 3 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "", (gogoproto.embed) = true]; + // The name of the table being audited. + string table_name = 4 [(gogoproto.jsontag) = ",omitempty"]; + // How the table was accessed (r=read / rw=read/write). + string access_mode = 5 [(gogoproto.jsontag) = ",omitempty", (gogoproto.moretags) = "redact:\"nonsensitive\""]; +} + + +// Category: SQL Slow Query Log +// Channel: SQL_PERF +// +// Events in this category report slow query execution. +// +// Note: these events are not written to `system.eventlog`, even +// when the cluster setting `system.eventlog.enabled` is set. They +// are only emitted via external logging. +// + +// SlowQuery is recorded when a query triggers the "slow query" condition. +// +// As of this writing, the condition requires: +// - the cluster setting `sql.log.slow_query.latency_threshold` +// set to a non-zero value, AND +// - EITHER of the following conditions: +// - the actual age of the query exceeds the configured threshold; OR +// - the query performs a full table/index scan. +message SlowQuery { + CommonEventDetails common = 1 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "", (gogoproto.embed) = true]; + CommonSQLEventDetails sql = 2 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "", (gogoproto.embed) = true]; + CommonSQLExecDetails exec = 3 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "", (gogoproto.embed) = true]; +} + +// Category: SQL Slow Query Log (Internal) +// Channel: SQL_INTERNAL_PERF +// +// Events in this category report slow query execution by +// internal executors, i.e. when CockroachDB internally issues +// SQL statements. +// +// Note: these events are not written to `system.eventlog`, even +// when the cluster setting `system.eventlog.enabled` is set. They +// are only emitted via external logging. + +// SlowQueryInternal is recorded when a query triggers the "slow query" condition, +// and the cluster setting `sql.log.slow_query.internal_queries.enabled` is +// set. +// See the documentation for the event type `slow_query` for details about +// the "slow query" condition. +message SlowQueryInternal { + CommonEventDetails common = 1 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "", (gogoproto.embed) = true]; + CommonSQLEventDetails sql = 2 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "", (gogoproto.embed) = true]; + CommonSQLExecDetails exec = 3 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "", (gogoproto.embed) = true]; +} + +// Category: SQL Execution Log +// Channel: SQL_EXEC +// +// Events in this category report executed queries. +// +// Note: these events are not written to `system.eventlog`, even +// when the cluster setting `system.eventlog.enabled` is set. They +// are only emitted via external logging. + +// QueryExecute is recorded when a query is executed, +// and the cluster setting `sql.trace.log_statement_execute` is set. +message QueryExecute { + CommonEventDetails common = 1 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "", (gogoproto.embed) = true]; + CommonSQLEventDetails sql = 2 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "", (gogoproto.embed) = true]; + CommonSQLExecDetails exec = 3 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "", (gogoproto.embed) = true]; +}