feat: integrate observability
This commit is contained in:
123
packages/observability/README.md
Normal file
123
packages/observability/README.md
Normal file
@@ -0,0 +1,123 @@
|
||||
# @mintel/observability
|
||||
|
||||
Standardized observability package for the Mintel ecosystem, providing Umami analytics and Sentry/GlitchTip error tracking with a focus on privacy and ad-blocker resilience.
|
||||
|
||||
## Features
|
||||
|
||||
- **Umami Smart Proxy**: Track analytics without external scripts and hide your Website ID.
|
||||
- **Sentry Relay**: Bypass ad-blockers for error tracking by relaying envelopes through your own server.
|
||||
- **Unified API**: consistent interface for tracking across multiple projects.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pnpm add @mintel/observability @sentry/nextjs
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### 1. Unified Environment (via @mintel/next-utils)
|
||||
|
||||
Define the following environment variables:
|
||||
|
||||
```bash
|
||||
# Analytics
|
||||
UMAMI_WEBSITE_ID=your-website-id
|
||||
UMAMI_API_ENDPOINT=https://analytics.infra.mintel.me
|
||||
|
||||
# Error Tracking
|
||||
SENTRY_DSN=your-sentry-dsn
|
||||
```
|
||||
|
||||
Note: No `NEXT_PUBLIC_` prefix is required for these anymore, as they are handled by server-side proxies.
|
||||
|
||||
### 2. Analytics Setup
|
||||
|
||||
In your root layout:
|
||||
|
||||
```tsx
|
||||
import {
|
||||
AnalyticsContextProvider,
|
||||
AnalyticsAutoTracker,
|
||||
UmamiAnalyticsService,
|
||||
} from "@mintel/observability";
|
||||
|
||||
const analytics = new UmamiAnalyticsService({
|
||||
enabled: true,
|
||||
websiteId: process.env.UMAMI_WEBSITE_ID, // Server-side
|
||||
apiEndpoint:
|
||||
typeof window === "undefined" ? process.env.UMAMI_API_ENDPOINT : "/stats",
|
||||
});
|
||||
|
||||
export default function Layout({ children }) {
|
||||
return (
|
||||
<AnalyticsContextProvider service={analytics}>
|
||||
<AnalyticsAutoTracker />
|
||||
{children}
|
||||
</AnalyticsContextProvider>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Route Handlers
|
||||
|
||||
Create a proxy for Umami:
|
||||
`app/stats/api/send/route.ts`
|
||||
|
||||
```ts
|
||||
import { createUmamiProxyHandler } from "@mintel/observability";
|
||||
export const POST = await createUmamiProxyHandler({
|
||||
websiteId: process.env.UMAMI_WEBSITE_ID,
|
||||
apiEndpoint: process.env.UMAMI_API_ENDPOINT,
|
||||
});
|
||||
```
|
||||
|
||||
Create a relay for Sentry:
|
||||
`app/errors/api/relay/route.ts`
|
||||
|
||||
```ts
|
||||
import { createSentryRelayHandler } from "@mintel/observability";
|
||||
export const POST = await createSentryRelayHandler({
|
||||
dsn: process.env.SENTRY_DSN,
|
||||
});
|
||||
```
|
||||
|
||||
### 4. Notification Setup (Server-side)
|
||||
|
||||
```ts
|
||||
import { GotifyNotificationService } from "@mintel/observability";
|
||||
|
||||
const notifications = new GotifyNotificationService({
|
||||
enabled: true,
|
||||
url: process.env.GOTIFY_URL,
|
||||
token: process.env.GOTIFY_TOKEN,
|
||||
});
|
||||
|
||||
await notifications.notify({
|
||||
title: "Lead Capture",
|
||||
message: "New contact form submission",
|
||||
priority: 5,
|
||||
});
|
||||
```
|
||||
|
||||
### 5. Sentry Configuration
|
||||
|
||||
Use `initSentry` in your `sentry.server.config.ts` and `sentry.client.config.ts`.
|
||||
|
||||
On the client, use the tunnel:
|
||||
|
||||
```ts
|
||||
initSentry({
|
||||
dsn: "https://public@errors.infra.mintel.me/1", // Placeholder
|
||||
tunnel: "/errors/api/relay",
|
||||
});
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
This package implements the **Smart Proxy** pattern:
|
||||
|
||||
- The client NEVER knows the real `UMAMI_WEBSITE_ID`.
|
||||
- Tracking events are sent to your own domain (`/stats/api/send`).
|
||||
- Your server injects the secret ID and forwards to Umami.
|
||||
- This bypasses ad-blockers and keeps your configuration secure.
|
||||
Reference in New Issue
Block a user