Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions crates/clickhouse-cloud-api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ Requires Rust 1.94 or later.

## Updated Cloud API surface

`ClickStackLogSource` and `ClickStackLogSourceResponse` gain optional
`event_name_expression` and `severity_number_expression`, the expressions for
the OpenTelemetry log `EventName` and numeric `SeverityNumber` (1-24). `TryFrom`
carries them back to the request type. Struct-literal callers need the new
fields as `None` or `..Default::default()`.

`ClickPipeMongoDBPipeTableMapping` gains optional `mongo_config`
(`ClickPipeMongoDBTableConfig`), per-collection MongoDB options. Its one field,
the required `persist_deleted_documents`, keeps the full document as it was
Expand Down
2 changes: 2 additions & 0 deletions crates/clickhouse-cloud-api/src/convert/clickstack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ impl TryFrom<ClickStackLogSourceResponse> for ClickStackLogSource {
disabled: value.disabled,
displayed_timestamp_value_expression: value.displayed_timestamp_value_expression,
event_attributes_expression: value.event_attributes_expression,
event_name_expression: value.event_name_expression,
filter_settings: value.filter_settings.map(TryInto::try_into).transpose()?,
from: from.try_into()?,
highlighted_row_attribute_expressions: value
Expand Down Expand Up @@ -200,6 +201,7 @@ impl TryFrom<ClickStackLogSourceResponse> for ClickStackLogSource {
section: value.section,
service_name_expression: value.service_name_expression,
service_version_expression: value.service_version_expression,
severity_number_expression: value.severity_number_expression,
severity_text_expression: value.severity_text_expression,
span_id_expression: value.span_id_expression,
timestamp_value_expression,
Expand Down
20 changes: 20 additions & 0 deletions crates/clickhouse-cloud-api/src/models/clickstack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3905,6 +3905,11 @@ pub struct ClickStackLogSource {
skip_serializing_if = "Option::is_none"
)]
pub event_attributes_expression: Option<String>,
#[serde(
rename = "eventNameExpression",
skip_serializing_if = "Option::is_none"
)]
pub event_name_expression: Option<String>,
#[serde(rename = "filterSettings", skip_serializing_if = "Option::is_none")]
pub filter_settings: Option<ClickStackSourceFilterSettings>,
pub from: ClickStackSourceFrom,
Expand Down Expand Up @@ -3959,6 +3964,11 @@ pub struct ClickStackLogSource {
skip_serializing_if = "Option::is_none"
)]
pub service_name_expression: Option<String>,
#[serde(
rename = "severityNumberExpression",
skip_serializing_if = "Option::is_none"
)]
pub severity_number_expression: Option<String>,
#[serde(
rename = "severityTextExpression",
skip_serializing_if = "Option::is_none"
Expand Down Expand Up @@ -4013,6 +4023,11 @@ pub struct ClickStackLogSourceResponse {
skip_serializing_if = "Option::is_none"
)]
pub event_attributes_expression: Option<String>,
#[serde(
rename = "eventNameExpression",
skip_serializing_if = "Option::is_none"
)]
pub event_name_expression: Option<String>,
#[serde(rename = "filterSettings", skip_serializing_if = "Option::is_none")]
pub filter_settings: Option<ClickStackSourceFilterSettingsResponse>,
#[serde(skip_serializing_if = "Option::is_none")]
Expand Down Expand Up @@ -4070,6 +4085,11 @@ pub struct ClickStackLogSourceResponse {
skip_serializing_if = "Option::is_none"
)]
pub service_name_expression: Option<String>,
#[serde(
rename = "severityNumberExpression",
skip_serializing_if = "Option::is_none"
)]
pub severity_number_expression: Option<String>,
#[serde(
rename = "severityTextExpression",
skip_serializing_if = "Option::is_none"
Expand Down
49 changes: 45 additions & 4 deletions crates/clickhouse-cloud-api/tests/models_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6919,9 +6919,10 @@ fn deserialize_clickstack_webhook_unknown_service_round_trips() {

#[test]
fn clickstack_source_expression_fields_missing_or_null_are_none() {
// `orderByExpression` (log, trace), `resourceAttributesExpression`
// (session), and the trace-only display, sampling and span-link
// expressions are optional in the spec: absent or `null` lands as `None`
// `orderByExpression` (log, trace), the log-only OpenTelemetry
// `eventNameExpression` and `severityNumberExpression`,
// `resourceAttributesExpression` (session), and the trace-only display,
// sampling and span-link expressions are optional in the spec: absent or `null` lands as `None`
// on the response variants and is omitted from the request variants.
let log = serde_json::json!({
"kind": "log",
Expand Down Expand Up @@ -6967,9 +6968,17 @@ fn clickstack_source_expression_fields_missing_or_null_are_none() {
"spanLinksValueExpression",
];

for payload in [log.clone(), with_nulls(&log, &["orderByExpression"])] {
let log_keys = [
"eventNameExpression",
"orderByExpression",
"severityNumberExpression",
];

for payload in [log.clone(), with_nulls(&log, &log_keys)] {
let response: ClickStackLogSourceResponse = serde_json::from_value(payload).unwrap();
assert_eq!(response.event_name_expression, None);
assert_eq!(response.order_by_expression, None);
assert_eq!(response.severity_number_expression, None);
let request = ClickStackLogSource::try_from(response).unwrap();
assert_eq!(serde_json::to_value(&request).unwrap(), log);
}
Expand All @@ -6996,11 +7005,15 @@ fn clickstack_source_expression_fields_missing_or_null_are_none() {
#[test]
fn clickstack_source_expression_fields_serialize_with_their_wire_names() {
let log = ClickStackLogSource {
event_name_expression: Some("EventName".to_string()),
order_by_expression: Some("Timestamp DESC".to_string()),
severity_number_expression: Some("SeverityNumber".to_string()),
..Default::default()
};
let v = serde_json::to_value(&log).unwrap();
assert_eq!(v["eventNameExpression"], "EventName");
assert_eq!(v["orderByExpression"], "Timestamp DESC");
assert_eq!(v["severityNumberExpression"], "SeverityNumber");

let session = ClickStackSessionSource {
resource_attributes_expression: Some("ResourceAttributes".to_string()),
Expand All @@ -7023,6 +7036,34 @@ fn clickstack_source_expression_fields_serialize_with_their_wire_names() {
assert_eq!(v["spanLinksValueExpression"], "Links");
}

#[test]
fn clickstack_log_source_otel_expressions_write_back() {
let wire = serde_json::json!({
"kind": "log",
"name": "logs",
"connection": "conn-1",
"defaultTableSelectExpression": "*",
"from": {"databaseName": "default", "tableName": "logs"},
"timestampValueExpression": "Timestamp",
"eventNameExpression": "EventName",
"severityNumberExpression": "SeverityNumber",
"severityTextExpression": "SeverityText",
});
let response: ClickStackLogSourceResponse = serde_json::from_value(wire.clone()).unwrap();
assert_eq!(response.event_name_expression.as_deref(), Some("EventName"));
assert_eq!(
response.severity_number_expression.as_deref(),
Some("SeverityNumber")
);
let request = ClickStackLogSource::try_from(response).unwrap();
assert_eq!(request.event_name_expression.as_deref(), Some("EventName"));
assert_eq!(
request.severity_number_expression.as_deref(),
Some("SeverityNumber")
);
assert_eq!(serde_json::to_value(&request).unwrap(), wire);
}

#[test]
fn clickstack_validate_webhook_response_null_fields_are_none() {
let null: ClickStackValidateWebhookResponse =
Expand Down
Loading