Remote logging
SDKs send logs to Hypertune Edge in the background. This allows you to:
See how often different parts of your flag logic are evaluated, e.g. to see how often different targeting rules are evaluated and passed in realtime
Log analytics events
Log split exposures, e.g. for A/B tests, multivariate tests and machine learning loops
See any SDK errors from the Hypertune UI
Manually flush logs
You can manually trigger and wait for logs to be flushed with the flushLogs
method:
import { NextFetchEvent, NextRequest } from "next/server";
import getHypertune from "./lib/getHypertune";
export async function middleware(
req: NextRequest,
context: NextFetchEvent
): Promise<void> {
const hypertune = await getHypertune();
const exampleFlag = hypertune.exampleFlag({ fallback: false });
console.log("Middleware Example Flag:", exampleFlag);
context.waitUntil(hypertune.flushLogs());
}
This is a requirement in serverless and edge environments like Vercel deployments, Cloudflare Workers, AWS Lambdas, etc, where background SDK tasks like flushing logs aren't guaranteed to execute.
Configuring log flushing
Flush interval
By default, SDKs flush logs to Hypertune Edge every 2 seconds. You can adjust this interval by setting the remoteLogging.flushIntervalMs
option. For example, to flush logs every 10 seconds, set this option to 10_000
. Setting the value to null
disables automatic log flushing.
Logging mode
The logging mode determines which SDK log messages, expression evaluations, A/B test exposures, and analytics events are sent to the remote server. You can control this behaviour using the remoteLogging.mode
initialization option:
Normal
All data is sent to the remote server.
Session
SDK log messages, expression evaluations, and A/B test exposures are deduplicated per session, based on the provided context. However, all analytics events are still sent to the remote server.
Off
No data is sent, making this mode ideal for local development or testing environments.
Logging endpoint
By default, SDKs flush all logs to Hypertune via the following endpoint: https://gcp.fasthorse.workers.dev/logs
You can change this endpoint by setting remoteLogging.endpointUrl
in your createSource
options:
import { createSource } from "../generated/hypertune";
const hypertuneSource = createSource({
token: process.env.HYPERTUNE_TOKEN!,
remoteLogging: {
endpointUrl: "https://yourdomain.com/api/hypertune-logs",
},
});
export default async function getHypertune() {
// Get flag updates in serverless environments
// await hypertuneSource.initIfNeeded();
return hypertuneSource.root({
args: {
context: {
environment:
process.env.NODE_ENV === "development"
? "development"
: "production",
user: { id: "1", name: "Test", email: "[email protected]" },
},
},
});
}
This enables you to send logs to your own server, where you can write them to your data warehouse or analytics platform, and optionally forward them to Hypertune:
import { NextResponse } from "next/server";
import {
CreateLogsInput,
prodLogsEndpointUrl,
} from "hypertune/dist/shared";
export const runtime = "edge";
export const dynamic = "force-dynamic";
export async function POST(request: Request) {
const body = (await request.json()) as CreateLogsInput;
console.log("events", body.events);
console.log("exposures", body.exposures);
// Forward logs to Hypertune
try {
await fetch(prodLogsEndpointUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
cache: "no-store",
});
} catch (error) {
console.error("Error forwarding logs to Hypertune:", error);
return NextResponse.json(
{ error: "Failed to forward logs to Hypertune" },
{ status: 500 },
);
}
// TODO: If successful, forward logs to own data warehouse too.
// Return an error response on failure.
return NextResponse.json({ success: true }, { status: 200 });
}
This setup also helps ensure you don't miss any logs due to ad blockers or network restrictions in the browser.
Last updated