Skip to content
Merged
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
27 changes: 27 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# VCS
.git
.gitignore
.github

# Docs / local artifacts
*.md
img/
output/

# Node / build outputs
node_modules
proxy/ui/node_modules
proxy/ui/dist

# Built binaries
promclick-proxy
promclick-writer
promclick-downsampler
proxy/proxy
*.exe

# Editor / OS
.idea
.vscode
*.swp
.DS_Store
78 changes: 78 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: Build Container Image

on:
push:
branches: [ "main" ]
tags: [ "v*" ]
pull_request:
branches: [ "main" ]
workflow_dispatch:

# Least privilege at the workflow level; the build job elevates to packages: write.
permissions:
contents: read

# Cancel superseded runs on the same ref (e.g. rapid PR pushes).
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository_owner }}/promclick

jobs:
build:
name: Build and push image
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: read
packages: write
steps:
- name: Check out code
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4

- name: Set up QEMU
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3

- name: Lowercase image name
id: image
run: echo "name=$(printf '%s' '${{ env.IMAGE_NAME }}' | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_OUTPUT"

- name: Log in to GHCR
# Only authenticate for pushes (pull requests from forks cannot access secrets).
if: github.event_name != 'pull_request'
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract image metadata
id: meta
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5
with:
images: ${{ env.REGISTRY }}/${{ steps.image.outputs.name }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha
type=raw,value=latest,enable={{is_default_branch}}

- name: Build and push
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
with:
context: .
platforms: linux/amd64,linux/arm64
# Push everywhere except pull requests (which only validate the build).
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@ promclick-downsampler
.DS_Store
Thumbs.db


# Built binaries
proxy/proxy
40 changes: 40 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Changelog

All notable changes to this project are documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added
- `NOTICE` file crediting the upstream [PromClick Authors](https://github.com/PromClick/PromClick)
and recording the Digitalis.io distribution copyright, preserving Apache-2.0 attribution.
- GitHub Actions workflow (`.github/workflows/build.yml`) that builds the multi-arch
container image (`linux/amd64`, `linux/arm64`) and publishes it to
`ghcr.io/digitalis-io/promclick` on pushes to `main` and on tags (`v*`), and can be
triggered manually. Pull requests build the image without pushing. Actions are pinned
to commit SHAs; the job has a build timeout and cancels superseded runs.
- Digitalis.io branding and an attribution section in the README.
- `.dockerignore` to shrink the build context.

### Changed
- Container image references now point to `ghcr.io/digitalis-io/promclick` instead of
the upstream `quay.io/hinski/promclick` (Helm chart values, `docker-compose.yaml`,
README examples).
- Helm chart `home`, `sources`, and `maintainers` metadata set to the Digitalis.io
distribution; chart version bumped to `1.1.0`.
- README clone URLs and Helm `oci://` pull path updated to the `digitalis-io` org.
- `Dockerfile` now cross-compiles the Go binaries on the native build platform
(`GOARCH=$TARGETARCH`, CGO disabled) instead of building under QEMU emulation,
making multi-arch image builds substantially faster.

### Security
- Fixed an SQL-injection vector in the OTel metadata/series handlers: `chEscape`
now escapes backslashes before single quotes so ClickHouse string literals cannot
be broken out of via a trailing backslash in request parameters.

## [0.1.0]

Initial upstream release vendored into the Digitalis.io distribution. See the
[upstream project](https://github.com/PromClick/PromClick) for the original history.
15 changes: 10 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
FROM node:20-alpine AS frontend
# Frontend output is architecture-independent, so build it once on the native
# build platform regardless of the target arch.
FROM --platform=$BUILDPLATFORM node:20-alpine AS frontend
WORKDIR /ui
COPY proxy/ui/package*.json ./
RUN npm ci
COPY proxy/ui/ .
RUN npm run build

FROM golang:1.24-alpine AS builder
# Build on the native platform and cross-compile with GOARCH (CGO is disabled,
# so no emulation is needed) — far faster than building under QEMU per arch.
FROM --platform=$BUILDPLATFORM golang:1.24-alpine AS builder
ARG TARGETARCH
WORKDIR /src
COPY go.work go.work.sum ./
COPY go.mod go.sum ./
COPY proxy/go.mod proxy/go.sum ./proxy/
RUN cd proxy && go mod download
COPY . .
COPY --from=frontend /ui/dist ./proxy/ui/dist
RUN cd proxy && CGO_ENABLED=0 go build -o /usr/local/bin/promclick-proxy ./cmd/proxy/ \
&& CGO_ENABLED=0 go build -o /usr/local/bin/promclick-writer ./cmd/writer/ \
&& CGO_ENABLED=0 go build -o /usr/local/bin/promclick-downsampler ./cmd/downsampler/
RUN cd proxy && CGO_ENABLED=0 GOARCH=$TARGETARCH go build -o /usr/local/bin/promclick-proxy ./cmd/proxy/ \
&& CGO_ENABLED=0 GOARCH=$TARGETARCH go build -o /usr/local/bin/promclick-writer ./cmd/writer/ \
&& CGO_ENABLED=0 GOARCH=$TARGETARCH go build -o /usr/local/bin/promclick-downsampler ./cmd/downsampler/

FROM alpine:3.20
RUN apk add --no-cache ca-certificates
Expand Down
3 changes: 2 additions & 1 deletion LICENSE.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,8 @@

END OF TERMS AND CONDITIONS

Copyright 2026 Authors of PromClick
Copyright 2026 The PromClick Authors (https://github.com/PromClick/PromClick)
Modifications Copyright 2026 Digitalis.io Ltd. (https://digitalis.io)

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
33 changes: 33 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
PromClick
=========

PromClick is a PromQL-to-SQL transpiler and Prometheus-compatible HTTP proxy
for ClickHouse.

This product includes software originally developed by the PromClick Authors:

Copyright 2026 The PromClick Authors
https://github.com/PromClick/PromClick

Original authors:
- Mateusz Darmetko (hinskii) <darmetkomateusz@gmail.com>
- Maciej Bekas <bekasmaciej@gmail.com>
- Pavel Kravtsov <kravtsovpo@gmail.com>

Licensed under the Apache License, Version 2.0 (the "License"); you may not use
the original work except in compliance with the License. A copy of the License
is included in the LICENSE.md file and is available at:

http://www.apache.org/licenses/LICENSE-2.0

--------------------------------------------------------------------------------

Modifications and packaging for the Digitalis.io distribution:

Copyright 2026 Digitalis.io Ltd.
https://digitalis.io

Digitalis.io vendors and maintains this distribution of PromClick. All original
copyright, patent, trademark, and attribution notices from the upstream project
are retained above as required by the Apache License, Version 2.0. The Digitalis
distribution is likewise made available under the Apache License, Version 2.0.
49 changes: 41 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
<p align="center">
<a href="https://digitalis.io">
<img src="https://digitalis-marketplace-assets.s3.us-east-1.amazonaws.com/DigitalisDigital_DigitalisFullLogoGradient+-+medium.png" alt="Digitalis.io" width="320"/>
</a>
</p>

# PromClick

> **A Digitalis.io distribution.** PromClick was originally created by the
> [PromClick Authors](https://github.com/PromClick/PromClick) and is licensed under
> Apache 2.0. Digitalis.io vendors and maintains this distribution, preserving the
> original attribution. See [Attribution](#attribution) and [`NOTICE`](NOTICE).

A Prometheus-compatible HTTP API that translates PromQL to ClickHouse SQL in real time.

**I was tired of Thanos. I was tired of Victoria Metrics. I was tired of Grafana Mimir and I'm tired of everything.**

You know the drill. You want long-term Prometheus storage. So you deploy Thanos - suddenly you have 47 YAML files, a sidecar, a store gateway, a compactor, a query frontend, and a PhD in distributed systems. Or you go with Mimir - congrats, you now operate a distributed hash ring and pray to the Memberlist gods every Tuesday.
Expand Down Expand Up @@ -83,11 +96,11 @@ TSDB Status page shows series count, sample count, top metrics, and label cardin
PromClick ships as a single Docker image with three binaries inside. Each handles one concern:

```bash
docker pull quay.io/hinski/promclick:0.1.0
docker pull ghcr.io/digitalis-io/promclick:0.1.0

docker run quay.io/hinski/promclick promclick-proxy --config proxy.yaml
docker run quay.io/hinski/promclick promclick-writer --config writer.yaml
docker run quay.io/hinski/promclick promclick-downsampler --config downsampler.yaml
docker run ghcr.io/digitalis-io/promclick promclick-proxy --config proxy.yaml
docker run ghcr.io/digitalis-io/promclick promclick-writer --config writer.yaml
docker run ghcr.io/digitalis-io/promclick promclick-downsampler --config downsampler.yaml
```

### promclick-proxy (query server)
Expand Down Expand Up @@ -190,7 +203,7 @@ interval: "1h" # re-check interval in daemon mode
### Docker Compose (all-in-one)

```bash
git clone https://github.com/PromClick/PromClick
git clone https://github.com/digitalis-io/PromClick
cd promclick
docker compose up -d

Expand Down Expand Up @@ -572,7 +585,7 @@ With full support for: `on()`, `ignoring()`, `group_left()`, `group_right()`, `b
## Quick Start

```bash
git clone https://github.com/PromClick/PromClick
git clone https://github.com/digitalis-io/PromClick
cd promclick
docker compose up -d
```
Expand All @@ -593,7 +606,7 @@ The compose stack runs everything: ClickHouse, Prometheus, Node Exporter, PromCl
Yes, there's a Helm chart.

```bash
helm pull oci://ghcr.io/promclick/promclick-chart --version <version>
helm pull oci://ghcr.io/digitalis-io/promclick-chart --version <version>
```

---
Expand Down Expand Up @@ -639,9 +652,29 @@ If you already run ClickHouse, PromClick gives you infinite Prometheus retention

---

## Attribution

PromClick was originally created by the
[PromClick Authors](https://github.com/PromClick/PromClick) — Mateusz Darmetko
(hinskii), Maciej Bekas, and Pavel Kravtsov — and released under the Apache
License 2.0.

This repository is the **Digitalis.io distribution** of PromClick. Digitalis.io
vendors and maintains it, preserving all upstream copyright and attribution
notices as required by the licence. The full attribution is recorded in the
[`NOTICE`](NOTICE) file.

## License

Apache 2.0
Licensed under the [Apache License, Version 2.0](LICENSE.md).

- Original work © The PromClick Authors.
- Modifications and packaging © Digitalis.io Ltd.

## Contact

Maintained by [Digitalis.io](https://digitalis.io). For support, get in touch at
[digitalis.io/contact](https://digitalis.io/contact).

---

Expand Down
9 changes: 8 additions & 1 deletion charts/promclick-chart/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,12 @@ apiVersion: v2
name: promclick-chart
description: PromClick is a PromQL-to-SQL transpiler + HTTP proxy that makes ClickHouse speak Prometheus.
type: application
version: 1.0.0
version: 1.1.0
appVersion: "0.1.0"
home: https://github.com/digitalis-io/PromClick
sources:
- https://github.com/digitalis-io/PromClick
- https://github.com/PromClick/PromClick
maintainers:
- name: Digitalis.io
url: https://digitalis.io
6 changes: 3 additions & 3 deletions charts/promclick-chart/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ deployments:
promClickProxy:
replicas: 1
image:
repository: quay.io/hinski/promclick
repository: ghcr.io/digitalis-io/promclick
# tag: 0.1.0 # tags can be overriden like this, by default it takes appVersion from Chart.yaml
name: promclick-proxy
command: ["promclick-proxy"]
Expand Down Expand Up @@ -50,7 +50,7 @@ deployments:
promClickWriter:
replicas: 1
image:
repository: quay.io/hinski/promclick
repository: ghcr.io/digitalis-io/promclick
# tag: 0.1.0 # tags can be overriden like this, by default it takes appVersion from Chart.yaml
name: promclick-writter
command: ["promclick-proxy"]
Expand Down Expand Up @@ -97,7 +97,7 @@ deployments:
promClickDownsampler:
replicas: 1
image:
repository: quay.io/hinski/promclick
repository: ghcr.io/digitalis-io/promclick
# tag: 0.1.0 # tags can be overriden like this, by default it takes appVersion from Chart.yaml
name: promclick-downsampler
service:
Expand Down
11 changes: 11 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@ type SchemaConfig struct {
ExtractedColumns []ExtractedColumn `yaml:"extracted_columns"`
Downsampling DownsamplingConfig `yaml:"downsampling"`
TimestampIsInt bool `yaml:"timestamp_is_int"` // true if timestamp column is Int64 (unix_milli), false if DateTime64

// Mode selects the read model. "" (default) is the Prometheus two-table
// layout (samples + time_series JOIN). "otel" reads the OpenTelemetry
// ClickHouse-exporter metric tables directly (single wide row per datapoint:
// MetricName / TimeUnix / Value / Attributes+ResourceAttributes Maps), with
// no fingerprint column or time_series table — fingerprint and labels are
// computed in SQL. See renderOTel in the translator.
Mode string `yaml:"mode"`
// Tables lists the OTel metric tables to UNION in "otel" mode (e.g.
// otel_metrics_gauge_dist, otel_metrics_sum_dist). Ignored unless Mode=="otel".
Tables []string `yaml:"tables"`
}

type DownsamplingConfig struct {
Expand Down
Loading
Loading