1use chrono::{DateTime, Utc};
13use mz_audit_log::ObjectType;
14use mz_sql::catalog::EnvironmentId;
15use mz_sql_parser::ast::StatementKind;
16use serde::{Deserialize, Serialize};
17use serde_json::json;
18use uuid::Uuid;
19
20#[derive(Debug, Clone, Default)]
22pub struct EventDetails<'a> {
23 pub user_id: Option<Uuid>,
25 pub application_name: Option<&'a str>,
28 pub timestamp: Option<DateTime<Utc>>,
30}
31
32pub trait SegmentClientExt {
34 fn environment_track<S>(
36 &self,
37 environment_id: &EnvironmentId,
38 event: S,
39 properties: serde_json::Value,
40 details: EventDetails<'_>,
41 ) where
42 S: Into<String>;
43}
44
45impl SegmentClientExt for mz_segment::Client {
46 fn environment_track<S>(
55 &self,
56 environment_id: &EnvironmentId,
57 event: S,
58 mut properties: serde_json::Value,
59 EventDetails {
60 user_id,
61 timestamp,
62 application_name,
63 }: EventDetails<'_>,
64 ) where
65 S: Into<String>,
66 {
67 {
68 let properties = match &mut properties {
69 serde_json::Value::Object(map) => map,
70 _ => {
71 panic!("SegmentClientExt::environment_track called with non-object properties")
72 }
73 };
74 properties.insert("event_source".into(), json!("environment"));
75 properties.insert(
76 "cloud_provider".into(),
77 json!(environment_id.cloud_provider().to_string()),
78 );
79 properties.insert(
80 "cloud_provider_region".into(),
81 json!(environment_id.cloud_provider_region()),
82 );
83 if let Some(application_name) = application_name {
84 properties.insert("application_name".into(), json!(application_name));
85 }
86 }
87
88 let context = json!({
91 "group_id": environment_id.organization_id()
92 });
93
94 let user_id = user_id.unwrap_or_else(|| environment_id.organization_id());
97
98 self.track(user_id, event, properties, Some(context), timestamp);
99 }
100}
101
102#[derive(Clone, Debug, Serialize, Deserialize)]
104#[serde(rename_all = "kebab-case")]
105pub enum StatementFailureType {
106 ParseFailure,
108}
109
110impl StatementFailureType {
111 pub fn as_title_case(&self) -> &'static str {
113 match self {
114 StatementFailureType::ParseFailure => "Parse Failed",
115 }
116 }
117}
118
119serde_plain::derive_display_from_serialize!(StatementFailureType);
120
121#[derive(Serialize, Deserialize)]
123pub enum StatementAction {
124 Alter,
126 Create,
128}
129
130impl StatementAction {
131 pub fn as_title_case(&self) -> &'static str {
133 match self {
134 StatementAction::Alter => "Alter",
135 StatementAction::Create => "Create",
136 }
137 }
138}
139
140pub fn analyze_audited_statement(
145 statement: StatementKind,
146) -> Option<(StatementAction, ObjectType)> {
147 match statement {
148 StatementKind::AlterConnection => Some((StatementAction::Alter, ObjectType::Connection)),
149 StatementKind::AlterIndex => Some((StatementAction::Alter, ObjectType::Index)),
150 StatementKind::AlterRole => Some((StatementAction::Alter, ObjectType::Role)),
151 StatementKind::AlterSecret => Some((StatementAction::Alter, ObjectType::Secret)),
152 StatementKind::AlterSource => Some((StatementAction::Alter, ObjectType::Source)),
153 StatementKind::CreateCluster => Some((StatementAction::Create, ObjectType::Cluster)),
154 StatementKind::CreateClusterReplica => {
155 Some((StatementAction::Create, ObjectType::ClusterReplica))
156 }
157 StatementKind::CreateConnection => Some((StatementAction::Create, ObjectType::Connection)),
158 StatementKind::CreateDatabase => Some((StatementAction::Create, ObjectType::Database)),
159 StatementKind::CreateIndex => Some((StatementAction::Create, ObjectType::Index)),
160 StatementKind::CreateMaterializedView => {
161 Some((StatementAction::Create, ObjectType::MaterializedView))
162 }
163 StatementKind::CreateRole => Some((StatementAction::Create, ObjectType::Role)),
164 StatementKind::CreateSchema => Some((StatementAction::Create, ObjectType::Schema)),
165 StatementKind::CreateSecret => Some((StatementAction::Create, ObjectType::Secret)),
166 StatementKind::CreateSink => Some((StatementAction::Create, ObjectType::Sink)),
167 StatementKind::CreateSource => Some((StatementAction::Create, ObjectType::Source)),
168 StatementKind::CreateTable => Some((StatementAction::Create, ObjectType::Table)),
169 StatementKind::CreateView => Some((StatementAction::Create, ObjectType::View)),
170 _ => None,
171 }
172}