Skip to content

Commit ae60909

Browse files
committed
Configure tail worker and vite usage
1 parent 106c7ad commit ae60909

File tree

7 files changed

+4315
-806
lines changed

7 files changed

+4315
-806
lines changed

.env.example

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
INFLUXDB_HOST=http://localhost
2-
INFLUXDB_DATABASE=example
3-
INFLUXDB_METRIC=views
4-
INFLUXDB_USERNAME=admin
5-
INFLUXDB_PASSWORD=pass
1+
INFLUX_URL=http://localhost:8086
2+
INFLUX_TOKEN=example
3+
INFLUX_ORG=example
4+
INFLUX_BUCKET=example

index.js

Lines changed: 59 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,108 +1,75 @@
1-
const parser = require('ua-parser-js');
1+
import { InfluxDB, Point } from '@influxdata/influxdb-client';
22

3-
// settings
4-
const MAX_REQUESTS_PER_BATCH = process.env.MAX_REQUESTS_PER_BATCH || 150;
5-
const MAX_TIME_AWAIT_PER_BATCH = process.env.MAX_TIME_AWAIT_PER_BATCH || 10 * 1000;
3+
const INFLUX_URL = process.env.INFLUX_URL || 'http://localhost:8086';
4+
const INFLUX_TOKEN = process.env.INFLUX_TOKEN || '';
5+
const INFLUX_ORG = process.env.INFLUX_ORG || '';
6+
const INFLUX_BUCKET = process.env.INFLUX_BUCKET || '';
67

7-
const INFLUXDB_HOST = process.env.INFLUXDB_HOST;
8-
const INFLUXDB_DATABASE = process.env.INFLUXDB_DATABASE;
9-
const INFLUXDB_METRIC = process.env.INFLUXDB_METRIC;
10-
const INFLUXDB_USERNAME = process.env.INFLUXDB_USERNAME;
11-
const INFLUXDB_PASSWORD = process.env.INFLUXDB_PASSWORD;
12-
const INFLUXDB_URL = `${INFLUXDB_HOST}/write?db=${INFLUXDB_DATABASE}&precision=s&u=${INFLUXDB_USERNAME}&p=${INFLUXDB_PASSWORD}`;
8+
const client = new InfluxDB({ url: INFLUX_URL, token: INFLUX_TOKEN });
139

1410
// global vars
15-
let requests = [];
16-
let batchIsRunning = false;
11+
async function handleRequest(request, env, ctx) {
12+
// TODO: Replace
13+
return await fetch('http://httpbin.org/status/200');
14+
}
1715

18-
addEventListener('fetch', event => {
19-
event.passThroughOnException();
20-
event.respondWith(logRequests(event));
21-
})
16+
async function formatMetricPoint(request) {
17+
const url = new URL(request.url);
18+
const today = new Date();
2219

23-
async function logRequests(event) {
24-
let requestStartTime, requestEndTime;
25-
if (!batchIsRunning) {
26-
event.waitUntil(handleBatch(event));
27-
}
28-
if (requests.length >= MAX_REQUESTS_PER_BATCH) {
29-
event.waitUntil(sendMetricsToInfuxDB())
30-
}
31-
requestStartTime = Date.now();
32-
const response = await fetch(event.request);
33-
requestEndTime = Date.now();
20+
const origin = request.headers.get("origin") ?? "";
21+
const ip = request.headers.get("cf-connecting-ip") ?? "";
22+
const userAgent = request.headers.get("user-agent") ?? "";
23+
const country = request.headers.get("cf-ipcountry") ?? "unknown";
24+
const cache = request.headers.get("cf-cache-status") ?? "unknown";
25+
const service = new URL(origin).hostname.replaceAll(".", "-");
3426

35-
if (event.request.headers.get('DNT') === '1') {
36-
return response;
37-
}
27+
/**
28+
* For every origin that reports a page_view, visitors get a unique ID every
29+
* day. We don't log their IPs / UserAgents, but we do use them to calculate
30+
* their IDs. Visitor IDs let us determine uniqueness.
31+
*
32+
* This is also the strategy Plausible uses, and is a great balance between
33+
* usefulness and privacy.
34+
*/
35+
const visitorDigest = await crypto.subtle.digest(
36+
"SHA-256",
37+
encoder.encode(today.toDateString() + ip + userAgent),
38+
);
39+
const visitor = Array.from(new Uint8Array(visitorDigest))
40+
.map((b) => b.toString(16).padStart(2, "0"))
41+
.join("");
3842

39-
requests.push(getRequestData(event.request, response, requestStartTime, requestEndTime));
43+
const point = new Point('request')
44+
.tag('url', url.toString())
45+
.tag('hostname', url.hostname)
46+
.tag('pathname', url.pathname)
47+
.tag('method', request.method)
48+
.tag('cf_cache', cache)
49+
.tag('country', country)
50+
.tag('service', service)
51+
.tag('visitor', visitor)
52+
.timestamp(today);
4053

41-
return response;
54+
return point;
4255
}
4356

44-
async function handleBatch(event) {
45-
batchIsRunning = true;
46-
await sleep(MAX_TIME_AWAIT_PER_BATCH);
47-
try {
48-
if (requests.length) event.waitUntil(sendMetricsToInfuxDB())
49-
} catch (e) {
50-
console.error(e);
51-
}
52-
requests = [];
53-
batchIsRunning = false;
54-
}
57+
async function handleMetrics(events, env, ctx) {
58+
const writeApi = client.getWriteApi(INFLUX_ORG, INFLUX_BUCKET);
59+
for (const event of events) {
60+
const point = formatMetricPoint(event.request);
5561

56-
function sleep(ms) {
57-
return new Promise(resolve => {
58-
setTimeout(resolve, ms)
59-
})
60-
}
62+
console.log(point)
63+
writeApi.writePoint(point);
6164

62-
function getRequestData(request, response, startTime, endTime) {
63-
const cfData = request.cf || {};
64-
const timestamp = Math.floor(Date.now() / 1000);
65-
const originResponse = response || {};
66-
return {
67-
'timestamp': timestamp,
68-
'userAgent': request.headers.get('user-agent'),
69-
'referer': request.headers.get('Referer'),
70-
'ip': request.headers.get('CF-Connecting-IP'),
71-
'countryCode': cfData.country,
72-
'url': request.url,
73-
'method': request.method,
74-
'status': originResponse.status,
75-
'originTime': (endTime - startTime),
76-
'cfCache': (originResponse) ? (response.headers.get('CF-Cache-Status') || 'miss') : 'miss',
77-
};
78-
79-
}
80-
81-
function formMetricLine(data) {
82-
let referer;
83-
const url = new URL(data.url);
84-
const utmSource = url.searchParams.get('utm_source') || 'empty';
85-
const ua = parser(data.userAgent);
86-
try {
87-
referer = new URL(data.referer);
88-
} catch {
89-
referer = {
90-
hostname: 'empty'
91-
};
9265
}
93-
return `${INFLUXDB_METRIC},status_code=${data.status},url=${data.url},hostname=${url.hostname},pathname=${url.pathname},method=${data.method},cf_cache=${data.cfCache},country=${data.countryCode},referer=${referer.hostname},utm_source=${utmSource},browser=${ua.browser.name},os=${ua.os.name},device=${ua.device.type} duration=${data.originTime} ${data.timestamp}`
94-
}
9566

96-
async function sendMetricsToInfuxDB() {
97-
const metrics = requests.map(formMetricLine).join('\n');
98-
try {
99-
return fetch(INFLUXDB_URL, {
100-
method: 'POST',
101-
body: metrics,
102-
}).then(function (r) {
103-
return r;
104-
});
105-
} catch (err) {
106-
console.log(err.stack || err);
107-
}
67+
ctx.waitUntil(
68+
writeApi.close()
69+
)
10870
}
71+
72+
export default {
73+
fetch: handleRequest,
74+
tail: handleMetrics,
75+
}

0 commit comments

Comments
 (0)