Skip to content
Merged

0.8.6 #184

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 CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ 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).


## [0.8.6] - 2026-03-31

### Fixed
- **ClickHouse traces/metrics data-availability always empty**: `queryTraces` and `queryMetrics` passed raw `0` for epoch dates as `DateTime64(3)` parameter, which ClickHouse can't parse; now uses the same `toDateTime64()` clamp used by log queries
- **Stale session after volume reset**: dashboard only checked `localStorage` for a token without validating it against the backend; now calls `/auth/me` on load and auto-logs out if the session is invalid

## [0.8.5] - 2026-03-28

### Security
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@
<a href="https://codecov.io/gh/logtide-dev/logtide"><img src="https://codecov.io/gh/logtide-dev/logtide/branch/main/graph/badge.svg" alt="Coverage"></a>
<a href="https://hub.docker.com/r/logtide/backend"><img src="https://img.shields.io/docker/v/logtide/backend?label=docker&logo=docker" alt="Docker"></a>
<a href="https://artifacthub.io/packages/helm/logtide/logtide"><img src="https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/logtide" alt="Artifact Hub"></a>
<img src="https://img.shields.io/badge/version-0.8.5-blue.svg" alt="Version">
<img src="https://img.shields.io/badge/version-0.8.6-blue.svg" alt="Version">
<img src="https://img.shields.io/badge/license-AGPLv3-blue.svg" alt="License">
<img src="https://img.shields.io/badge/status-stable_alpha-success.svg" alt="Status">
</div>

<br />

> **🚀 RELEASE 0.8.5:** LogTide now supports **Multi-Engine Storage** (ClickHouse, MongoDB) and **Advanced Browser Observability**.
> **🚀 RELEASE 0.8.6:** LogTide now supports **Multi-Engine Storage** (ClickHouse, MongoDB) and **Advanced Browser Observability**.

---

Expand All @@ -46,7 +46,7 @@ Designed for teams that need **GDPR compliance**, **full data ownership**, and *
### Logs Explorer
![LogTide Logs](docs/images/logs.png)

### Performance & Metrics (New in 0.8.5)
### Performance & Metrics (New in 0.8.6)
![LogTide Metrics](docs/images/metrics.png)

### Distributed Tracing
Expand Down Expand Up @@ -124,7 +124,7 @@ We host it for you. Perfect for testing. [**Sign up at logtide.dev**](https://lo

---

## ✨ Core Features (v0.8.5)
## ✨ Core Features (v0.8.6)

* 🚀 **Multi-Engine Reservoir:** Pluggable storage layer supporting **TimescaleDB**, **ClickHouse**, and **MongoDB**.
* 🌐 **Browser SDK Enhancements:** Automatic collection of **Web Vitals** (LCP, INP, CLS), user session tracking, and click/network breadcrumbs.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "logtide",
"version": "0.8.5",
"version": "0.8.6",
"private": true,
"description": "LogTide - Self-hosted log management platform",
"author": "LogTide Team",
Expand Down
2 changes: 1 addition & 1 deletion packages/backend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@logtide/backend",
"version": "0.8.5",
"version": "0.8.6",
"private": true,
"description": "LogTide Backend API",
"type": "module",
Expand Down
2 changes: 1 addition & 1 deletion packages/backend/src/utils/internal-logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export async function initializeInternalLogging(): Promise<string | null> {
dsn,
service: process.env.SERVICE_NAME || 'logtide-backend',
environment: process.env.NODE_ENV || 'development',
release: process.env.npm_package_version || '0.8.5',
release: process.env.npm_package_version || '0.8.6',
batchSize: 5, // Smaller batch for internal logs to see them faster
flushInterval: 5000,
maxBufferSize: 1000,
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@logtide/frontend",
"version": "0.8.5",
"version": "0.8.6",
"private": true,
"description": "LogTide Frontend Dashboard",
"type": "module",
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/src/hooks.client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ if (dsn) {
dsn,
service: 'logtide-frontend-client',
environment: env.PUBLIC_NODE_ENV || 'production',
release: env.PUBLIC_APP_VERSION || '0.8.5',
release: env.PUBLIC_APP_VERSION || '0.8.6',
debug: env.PUBLIC_NODE_ENV === 'development',
browser: {
// Core Web Vitals (LCP, INP, CLS, TTFB)
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/src/hooks.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export const handle = dsn
dsn,
service: 'logtide-frontend',
environment: privateEnv?.NODE_ENV || 'production',
release: process.env.npm_package_version || '0.8.5', }) as unknown as Handle,
release: process.env.npm_package_version || '0.8.6', }) as unknown as Handle,
requestLogHandle,
configHandle
)
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/src/lib/components/Footer.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import Github from "@lucide/svelte/icons/github";

const version = "Alpha v0.8.5";
const version = "Alpha v0.8.6";
const currentYear = new Date().getFullYear();
const githubUrl = "https://github.com/logtide-dev/logtide";
</script>
Expand Down
12 changes: 11 additions & 1 deletion packages/frontend/src/lib/components/RequireOrganization.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,17 @@
}
} else {
// Standard mode: check for token
if (!$authStore.user) {
if (!$authStore.token) {
goto('/login');
return;
}

// Validate token against backend (catches stale localStorage tokens)
try {
const { user } = await authAPI.getMe($authStore.token);
authStore.updateUser(user);
} catch {
authStore.clearAuth();
goto('/login');
return;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/reservoir/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@logtide/reservoir",
"version": "0.8.5",
"version": "0.8.6",
"description": "Pluggable storage abstraction for Logtide log management",
"type": "module",
"main": "./dist/index.js",
Expand Down
54 changes: 27 additions & 27 deletions packages/reservoir/src/engines/clickhouse/clickhouse-engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ import type {
MetricsOverviewParams,
MetricsOverviewResult,
} from '../../core/types.js';
import { ClickHouseQueryTranslator } from './query-translator.js';
import { ClickHouseQueryTranslator, toDateTime64 } from './query-translator.js';

export interface ClickHouseEngineOptions {
/** Use an existing ClickHouse client instead of creating a new one */
Expand Down Expand Up @@ -841,9 +841,9 @@ export class ClickHouseEngine extends StorageEngine {

// Time range
conditions.push(`time ${params.fromExclusive ? '>' : '>='} {p_from:DateTime64(3)}`);
queryParams.p_from = Math.floor(params.from.getTime() / 1000);
queryParams.p_from = toDateTime64(params.from);
conditions.push(`time ${params.toExclusive ? '<' : '<='} {p_to:DateTime64(3)}`);
queryParams.p_to = Math.floor(params.to.getTime() / 1000);
queryParams.p_to = toDateTime64(params.to);

if (params.projectId) {
const pids = Array.isArray(params.projectId) ? params.projectId : [params.projectId];
Expand Down Expand Up @@ -920,9 +920,9 @@ export class ClickHouseEngine extends StorageEngine {
const queryParams: Record<string, unknown> = {};

conditions.push(`start_time >= {p_from:DateTime64(3)}`);
queryParams.p_from = Math.floor(params.from.getTime() / 1000);
queryParams.p_from = toDateTime64(params.from);
conditions.push(`start_time <= {p_to:DateTime64(3)}`);
queryParams.p_to = Math.floor(params.to.getTime() / 1000);
queryParams.p_to = toDateTime64(params.to);

if (params.projectId) {
const pids = Array.isArray(params.projectId) ? params.projectId : [params.projectId];
Expand Down Expand Up @@ -996,11 +996,11 @@ export class ClickHouseEngine extends StorageEngine {

if (from) {
timeFilter += ` AND child.start_time >= {p_from:DateTime64(3)}`;
queryParams.p_from = Math.floor(from.getTime() / 1000);
queryParams.p_from = toDateTime64(from);
}
if (to) {
timeFilter += ` AND child.start_time <= {p_to:DateTime64(3)}`;
queryParams.p_to = Math.floor(to.getTime() / 1000);
queryParams.p_to = toDateTime64(to);
}

const resultSet = await client.query({
Expand Down Expand Up @@ -1058,8 +1058,8 @@ export class ClickHouseEngine extends StorageEngine {
];
const queryParams: Record<string, unknown> = {
p_pids: pids,
p_from: Math.floor(params.from.getTime() / 1000),
p_to: Math.floor(params.to.getTime() / 1000),
p_from: toDateTime64(params.from),
p_to: toDateTime64(params.to),
};

if (params.serviceName) {
Expand Down Expand Up @@ -1161,9 +1161,9 @@ export class ClickHouseEngine extends StorageEngine {

// Time range
conditions.push(`time ${params.fromExclusive ? '>' : '>='} {p_from:DateTime64(3)}`);
queryParams.p_from = Math.floor(params.from.getTime() / 1000);
queryParams.p_from = toDateTime64(params.from);
conditions.push(`time ${params.toExclusive ? '<' : '<='} {p_to:DateTime64(3)}`);
queryParams.p_to = Math.floor(params.to.getTime() / 1000);
queryParams.p_to = toDateTime64(params.to);

if (params.organizationId) {
const oids = Array.isArray(params.organizationId) ? params.organizationId : [params.organizationId];
Expand Down Expand Up @@ -1305,9 +1305,9 @@ export class ClickHouseEngine extends StorageEngine {
queryParams.p_pids = pids;

conditions.push(`time >= {p_from:DateTime64(3)}`);
queryParams.p_from = Math.floor(params.from.getTime() / 1000);
queryParams.p_from = toDateTime64(params.from);
conditions.push(`time <= {p_to:DateTime64(3)}`);
queryParams.p_to = Math.floor(params.to.getTime() / 1000);
queryParams.p_to = toDateTime64(params.to);

conditions.push(`metric_name = {p_name:String}`);
queryParams.p_name = params.metricName;
Expand Down Expand Up @@ -1442,8 +1442,8 @@ export class ClickHouseEngine extends StorageEngine {

const queryParams: Record<string, unknown> = {
p_pids: projectIds,
p_from: Math.floor(params.from.getTime() / 1000),
p_to: Math.floor(params.to.getTime() / 1000),
p_from: toDateTime64(params.from),
p_to: toDateTime64(params.to),
p_name: params.metricName,
};

Expand Down Expand Up @@ -1513,11 +1513,11 @@ export class ClickHouseEngine extends StorageEngine {
}
if (params.from) {
conditions.push(`time >= {p_from:DateTime64(3)}`);
queryParams.p_from = Math.floor(params.from.getTime() / 1000);
queryParams.p_from = toDateTime64(params.from);
}
if (params.to) {
conditions.push(`time <= {p_to:DateTime64(3)}`);
queryParams.p_to = Math.floor(params.to.getTime() / 1000);
queryParams.p_to = toDateTime64(params.to);
}

const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
Expand Down Expand Up @@ -1560,11 +1560,11 @@ export class ClickHouseEngine extends StorageEngine {
}
if (params.from) {
conditions.push(`time >= {p_from:DateTime64(3)}`);
queryParams.p_from = Math.floor(params.from.getTime() / 1000);
queryParams.p_from = toDateTime64(params.from);
}
if (params.to) {
conditions.push(`time <= {p_to:DateTime64(3)}`);
queryParams.p_to = Math.floor(params.to.getTime() / 1000);
queryParams.p_to = toDateTime64(params.to);
}

const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
Expand Down Expand Up @@ -1606,11 +1606,11 @@ export class ClickHouseEngine extends StorageEngine {
}
if (params.from) {
conditions.push(`time >= {p_from:DateTime64(3)}`);
queryParams.p_from = Math.floor(params.from.getTime() / 1000);
queryParams.p_from = toDateTime64(params.from);
}
if (params.to) {
conditions.push(`time <= {p_to:DateTime64(3)}`);
queryParams.p_to = Math.floor(params.to.getTime() / 1000);
queryParams.p_to = toDateTime64(params.to);
}

const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
Expand Down Expand Up @@ -1640,8 +1640,8 @@ export class ClickHouseEngine extends StorageEngine {
];
const queryParams: Record<string, unknown> = {
p_pids: pids,
p_from: Math.floor(params.from.getTime() / 1000),
p_to: Math.floor(params.to.getTime() / 1000),
p_from: toDateTime64(params.from),
p_to: toDateTime64(params.to),
};

if (params.metricName) {
Expand Down Expand Up @@ -1671,8 +1671,8 @@ export class ClickHouseEngine extends StorageEngine {
query: `ALTER TABLE metric_exemplars DELETE WHERE ${exemplarConditions.join(' AND ')}`,
query_params: {
p_pids: pids,
p_from: Math.floor(params.from.getTime() / 1000),
p_to: Math.floor(params.to.getTime() / 1000),
p_from: toDateTime64(params.from),
p_to: toDateTime64(params.to),
},
});

Expand All @@ -1685,8 +1685,8 @@ export class ClickHouseEngine extends StorageEngine {
const projectIds = Array.isArray(params.projectId) ? params.projectId : [params.projectId];
const queryParams: Record<string, unknown> = {
p_pids: projectIds,
p_from: Math.floor(params.from.getTime() / 1000),
p_to: Math.floor(params.to.getTime() / 1000),
p_from: toDateTime64(params.from),
p_to: toDateTime64(params.to),
};

let serviceFilter = '';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type {
} from '../../core/types.js';

/** ClickHouse can't parse 0 as DateTime64(3) — clamp to 1ms after epoch */
function toDateTime64(date: Date): number {
export function toDateTime64(date: Date): number {
return Math.max(date.getTime() / 1000, 0.001);
}

Expand Down
2 changes: 1 addition & 1 deletion packages/shared/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@logtide/shared",
"version": "0.8.5",
"version": "0.8.6",
"private": true,
"description": "Shared types, schemas and utilities for LogTide",
"type": "module",
Expand Down
Loading