Skip to content

DT-61: Implement ClickHouse client and create necessary tables and views#62

Merged
kigiri merged 7 commits intomasterfrom
61-click-house-config-for-deployments-logs
Sep 15, 2025
Merged

DT-61: Implement ClickHouse client and create necessary tables and views#62
kigiri merged 7 commits intomasterfrom
61-click-house-config-for-deployments-logs

Conversation

@abdotop
Copy link
Member

@abdotop abdotop commented Aug 29, 2025

No description provided.

@abdotop abdotop linked an issue Aug 29, 2025 that may be closed by this pull request
@abdotop abdotop force-pushed the 61-click-house-config-for-deployments-logs branch from d7d03f7 to c567b7f Compare August 29, 2025 10:17
query: `
CREATE TABLE IF NOT EXISTS logs (
deployment_id LowCardinality(String),
timestamp DateTime64(3, 'UTC') DEFAULT now64(3, 'UTC'),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 ?

INDEX idx_message message TYPE tokenbf_v1(8192, 3, 0) GRANULARITY 4
)
ENGINE = MergeTree
PARTITION BY toYYYYMMDD(timestamp)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to know more about this

@abdotop abdotop self-assigned this Aug 30, 2025
@abdotop abdotop force-pushed the 61-click-house-config-for-deployments-logs branch 2 times, most recently from a9e74ae to 4ea28b7 Compare August 30, 2025 16:31
@abdotop abdotop requested review from Copilot and kigiri August 30, 2025 16:33

This comment was marked as outdated.

@abdotop abdotop force-pushed the 61-click-house-config-for-deployments-logs branch from 4ea28b7 to 8e914e1 Compare August 30, 2025 16:36
@abdotop abdotop requested a review from Copilot August 30, 2025 16:37

This comment was marked as outdated.

@abdotop abdotop force-pushed the 61-click-house-config-for-deployments-logs branch from 8e914e1 to 66fb184 Compare August 30, 2025 16:38
@abdotop abdotop force-pushed the 61-click-house-config-for-deployments-logs branch from 66fb184 to 014ad5e Compare August 30, 2025 16:51
@abdotop abdotop requested a review from Copilot August 30, 2025 16:51
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This pull request implements ClickHouse integration for log storage and management, adding database client configuration and deployment token-based authentication for log ingestion.

  • Adds ClickHouse client with table creation for structured log storage
  • Implements deployment management API endpoints with encrypted token authentication
  • Integrates ClickHouse setup into the development and production workflows

Reviewed Changes

Copilot reviewed 10 out of 11 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tasks/clickhouse.ts Creates ClickHouse logs table with proper schema and partitioning
deno.json Adds ClickHouse dependency and integrates setup tasks into dev/prod workflows
api/user.ts Exports encryption functions for deployment token generation
api/server.ts Adds resource field to request context for deployment tracking
api/routes.ts Implements complete deployment CRUD API and log ingestion endpoint
api/lib/validator.ts Adds UNION validator for handling multiple input types
api/lib/env.ts Adds required ClickHouse environment variable validation
api/lib/context.ts Extends request context with resource tracking
api/click-house-client.ts Implements ClickHouse client and log insertion functionality
.env.test Adds ClickHouse configuration for test environment

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment on lines +224 to +233
return deployments.map(({ tokenSalt: _, ...d }) => {
return {
...d,
createdAt: d.createdAt,
updatedAt: d.updatedAt,
token: undefined,
sqlToken: undefined,
sqlEndpoint: undefined,
}
})
Copy link

Copilot AI Aug 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The explicit assignment of createdAt and updatedAt fields is redundant since they're already included in the spread operator ...d. These lines can be removed.

Copilot uses AI. Check for mistakes.
api/routes.ts Outdated
Comment on lines +250 to +251
createdAt: deployment.createdAt,
updatedAt: deployment.updatedAt,
Copy link

Copilot AI Aug 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The explicit assignment of createdAt and updatedAt fields is redundant since they're already included in the spread operator ...deployment. These lines can be removed.

Copilot uses AI. Check for mistakes.
api/routes.ts Outdated
Comment on lines +273 to +274
createdAt: deployment.createdAt,
updatedAt: deployment.updatedAt,
Copy link

Copilot AI Aug 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The explicit assignment of createdAt and updatedAt fields is redundant since they're already included in the spread operator ...deployment. These lines can be removed.

Copilot uses AI. Check for mistakes.
api/routes.ts Outdated
Comment on lines +292 to +293
createdAt: deployment.createdAt,
updatedAt: deployment.updatedAt,
Copy link

Copilot AI Aug 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The explicit assignment of createdAt and updatedAt fields is redundant since they're already included in the spread operator ...deployment. These lines can be removed.

Copilot uses AI. Check for mistakes.
api/routes.ts Outdated
Comment on lines +315 to +316
createdAt: deployment.createdAt,
updatedAt: deployment.updatedAt,
Copy link

Copilot AI Aug 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The explicit assignment of createdAt and updatedAt fields is redundant since they're already included in the spread operator ...deployment. These lines can be removed.

Copilot uses AI. Check for mistakes.
severity_text: STR(),
severity_number: NUM(),
attributes: OBJ({}),
event_name: STR(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

describe each fields, isn't severity_text & severity_number redundant ? do we ever use severity_number ?

api/routes.ts Outdated
return {
...d,
createdAt: d.createdAt,
updatedAt: d.updatedAt,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be fixed with a type assertion, not JS (IMO)

timestamp DateTime64(3, 'UTC') DEFAULT now64(3, 'UTC'),
observed_timestamp DateTime64(3, 'UTC') DEFAULT now64(3, 'UTC'),
trace_id UInt64,
span_id UInt64,
Copy link
Member

@kigiri kigiri Sep 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

trace_id & span_id should be FixedString(16) as per Otel spec:
https://opentelemetry.io/docs/specs/otel/logs/data-model/#trace-context-fields

To convert from our internal float64 id to their 128bit id we can do this:

function float64ToId128(id) {
  const id128 = new Uint8Array(16)
  crypto.getRandomValues(id128) // prefill with random values
  const view = new DataView(id128.buffer)
  view.setFloat64(8, id, false)
  return id128
}

observed_timestamp DateTime64(3, 'UTC') DEFAULT now64(3, 'UTC'),
trace_id UInt64,
span_id UInt64,
severity_number UInt8,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could store also the severity_string in the db and derive it from the severity_number just not take it as a parameter to the route, or do the oposite

severity_number UInt8,
attributes JSON,
event_name String,
context JSON
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove context and resource
and instead use "flattened" attributes for service

    -- Flattened resource fields
    service_name        LowCardinality(String),
    service_version     LowCardinality(String),
    service_instance_id String,

attributes JSON,
event_name String,
context JSON
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to be compliant, looks like we need a body, even if we don't use it we can make it nullable:

    -- Often empty, but kept for OTEL spec compliance
    body Nullable(String),

We could try to add support to set it from the API as a special attribute, could be use ingesting log that only have text and no attributes ?

@abdotop abdotop force-pushed the 61-click-house-config-for-deployments-logs branch 2 times, most recently from 698a7ca to 913ff62 Compare September 10, 2025 10:01
@abdotop abdotop force-pushed the 61-click-house-config-for-deployments-logs branch from 913ff62 to 0e431e1 Compare September 10, 2025 10:12
@abdotop abdotop force-pushed the 61-click-house-config-for-deployments-logs branch from 0e431e1 to 54ee31c Compare September 11, 2025 09:54

export function bytesToHex(bytes: Uint8Array) {
return Array.from(bytes).map((b) => b.toString(16).padStart(2, '0')).join('')
}
Copy link
Member

@kigiri kigiri Sep 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const numberToHex128 = (() => {
  const alphabet = new TextEncoder().encode("0123456789abcdef")
  const output = new Uint8Array(16)
  const view = new DataView(new Uint8Array(8).buffer)
  const dec = new TextDecoder()
  return (id: number) => {
    view.setFloat64(0, id, false)
    let i = -1
    while (++i < 8) {
      const x = view.getUint8(i)
      output[i * 2] = alphabet[x >> 4]
      output[i * 2 + 1] = alphabet[x & 0xF]
    }
    return dec.decode(output)
  }
})()

}

function toClickhouseDateTime(iso: string) {
// "2025-09-11T17:35:00.000Z" → "2025-09-11 17:35:00"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"2025-09-11T17:35:00.000Z".replace('T', ' ').slice(0, -5)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

span_id FixedString(16),
severity_number UInt8,
-- derived column, computed by DB from severity_number
severity_text String MATERIALIZED CASE
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be LowCardinality(String)

@abdotop abdotop force-pushed the 61-click-house-config-for-deployments-logs branch from e9d522e to 11636bb Compare September 12, 2025 12:49
data: LogsInput,
) {
const logsToInsert = Array.isArray(data) ? data : [data]
if (logsToInsert.length === 0) throw respond.NoContent()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it ok to throw a response ?

return respond.OK()
} catch (error) {
log.error('Error inserting logs into ClickHouse:', { error })
throw respond.InternalServerError()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here, shouldn't we just return in that case ?

@abdotop abdotop force-pushed the 61-click-house-config-for-deployments-logs branch 6 times, most recently from 3fb67ff to e1dac52 Compare September 15, 2025 09:51
@abdotop abdotop force-pushed the 61-click-house-config-for-deployments-logs branch from e1dac52 to a0e50df Compare September 15, 2025 09:54
{ project, team }: { project: Project; team: Team },
) => {
console.log(project)
console.log(team)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

???

@kigiri kigiri marked this pull request as ready for review September 15, 2025 10:45
@kigiri kigiri merged commit 61c7b47 into master Sep 15, 2025
2 checks passed
@kigiri kigiri deleted the 61-click-house-config-for-deployments-logs branch September 15, 2025 10:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Click-House config for deployments logs

3 participants