Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add cloudflare worker to collect API key usage inside Influx DB #1

Merged
merged 40 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
07f4429
Cache response inside cloudflare worker
pyropy Dec 10, 2024
6c5318d
Do not cache POST requests
pyropy Dec 10, 2024
e2ca738
Do not cache POST request responses
pyropy Dec 10, 2024
51b147b
Simplify request formating code
pyropy Dec 10, 2024
4c547d7
Remove unused function arguments
pyropy Dec 10, 2024
467e081
Use default project layout
pyropy Dec 10, 2024
0bba446
Update example env
pyropy Dec 10, 2024
15abebe
Move request logic to worker
pyropy Dec 10, 2024
5891c88
Add unit tests for worker.fetch
pyropy Dec 10, 2024
df26c99
Add basic docs
pyropy Dec 10, 2024
1ab824c
Update lib/request.js
pyropy Dec 11, 2024
3525f3e
Update lib/metrics.js
pyropy Dec 11, 2024
f6c88ac
Update lib/request.js
pyropy Dec 11, 2024
8732dc3
Update lib/request.js
pyropy Dec 11, 2024
882792d
Update .env.example
pyropy Dec 11, 2024
d27848d
Move all influx db related code to lib/influx.js
pyropy Dec 11, 2024
116b146
Add basic github actions
pyropy Dec 11, 2024
bb1ae1c
Fix failing test
pyropy Dec 11, 2024
a8d3bb9
Fix missing wranger.toml in test job
pyropy Dec 11, 2024
6b76ef4
Update readme with deployment steps
pyropy Dec 11, 2024
6143e4c
Fix README URL for getting CF API token
pyropy Dec 12, 2024
8c65bab
Improve api key parsing to be more readable
pyropy Dec 12, 2024
c3fd71f
Simplify worker code; Don't compress metrics
pyropy Dec 12, 2024
4bd5fb2
Remove unused env variable
pyropy Dec 12, 2024
700b15a
Report api key as value
pyropy Dec 12, 2024
201b375
Edit default env variables and secrets
pyropy Dec 12, 2024
7f844c6
Reformat files with newline at EOF
pyropy Dec 12, 2024
16cae7e
Refactor influx.js module
pyropy Dec 12, 2024
ef2ecd0
Reformat JSDoc
pyropy Dec 12, 2024
842eaf5
Update test name
pyropy Dec 12, 2024
81e8b56
Add table tests for influx lib
pyropy Dec 12, 2024
8fc77ed
Refactor how influx lib is tested
pyropy Dec 12, 2024
c43b0d5
Add test for reportRequestMetric
pyropy Dec 12, 2024
081d4ea
Improve influx test
pyropy Dec 13, 2024
bb531a9
Use envsubst to replace env vars in gh actions
pyropy Dec 13, 2024
357da93
Update lib/influx.js
pyropy Dec 16, 2024
82feb43
Update bin/worker.js
pyropy Dec 16, 2024
bdc81ee
Fix imports and mocks for renamed functions in tests
pyropy Dec 16, 2024
99c0884
Rename project to spark-stats-request-metrics
pyropy Dec 17, 2024
8f5ef87
Rename import for reporting metrics to influx
pyropy Dec 17, 2024
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
1 change: 1 addition & 0 deletions .dev.vars.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
INFLUX_TOKEN="example"
3 changes: 0 additions & 3 deletions .env.example

This file was deleted.

42 changes: 42 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: cp wrangler.toml.example wrangler.toml
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npm test

deploy:
if: github.ref == 'refs/heads/main'
needs: [test]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
preCommands: |
cp wranger.toml.example wrangler.toml
envsubst < wrangler.toml.example > wrangler.toml
pyropy marked this conversation as resolved.
Show resolved Hide resolved
postCommands: |
rm -f wrangler.toml
environment: production
secrets: |
INFLUX_TOKEN
env:
INFLUX_METRIC_NAME: ${{ env.INFLUX_METRIC }}
INFLUX_URL: ${{ env.INFLUX_URL }}
INFLUX_TOKEN: ${{ secrets.INFLUX_TOKEN }}
INFLUX_DATABASE: ${{ env.INFLUX_DATABASE }}
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
/dist
**/*.rs.bk
Cargo.lock
bin/
pkg/
wasm-pack.log
worker/
node_modules/
.cargo-ok
.env
.dev.vars
.wrangler
data/
config/
wrangler.toml
wrangler.toml
35 changes: 19 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,37 @@
# Cloudflare metrics worker

Send your page views from [Cloudflare worker](https://developers.cloudflare.com/workers/) to InfluxDB.
[Couldflare worker](https://developers.cloudflare.com/workers/) used to proxy requests to your application and send metrics to InfluxDB.

![Dashboard views](static/dashboard.png)
## Development

## Requirements

1. Your site need to be setup behind Cloudflare CDN.
2. You need to setup InfluxDB with external access (make sure you have set [authentication](https://docs.influxdata.com/influxdb/v1.7/administration/authentication_and_authorization/#set-up-authentication))
1. Make sure InfluxDB is hosted under [supported port](https://blog.cloudflare.com/cloudflare-now-supporting-more-ports/) for Workers. Best option is 80 or 443.

## How to use

1. Install wrangler package
1. Install dependencies

```
npm i @cloudflare/wrangler -g
npm install
```

2. Copy example files

```
cp .env.example .env
cp .dev.vars.example .dev.vars
cp wrangler.toml.example wrangler.toml
```

3. Deploy your worker to a site with wrangler
3. Edit secrets inside `.dev.vars` and environment variables inside `wrangler.toml` files

3. Run your worker

```
wrangler publish --env production
npm run dev
```

4. (Optional) If you're using Grafana with InfluxDB, then you can import [example Dashboard](static/dashboard.json) from first screen.
## Deployment to production

In order to deploy your worker via Github Actions, you need to have a [Cloudflare API token](https://developers.cloudflare.com/fundamentals/api/get-started/create-token/) and running instance of InfluxDB.

Add generated API token to Github secrets as `CLOUDFLARE_API_TOKEN` and authentication token under `INFLUX_TOKEN`.

Other required environment variables include the following:
- `INFLUX_URL` - InfluxDB URL
- `INFLUX_DATABASE` - InfluxDB database (bucket) name
- `INFLUX_METRIC_NAME` - InfluxDB metric name
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from(bucket: "api-observability")

I find this confusing. We have spark-api and spark-stats projects, this bucket name leads me to think about spark-api, while we are reporting telemetry for spark-stats.

Proposed bucket name: spark-stats-telemetry or simply spark-stats.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 to spark-stats, spark-stats-telemetry is redundant I think in the context of InfluxDB

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's go with spark-stats once we have this finished. I'll keep this bucket name while in development.

9 changes: 9 additions & 0 deletions bin/worker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { reportRequestMetrics as reportRequestMetricsToInflux } from '../lib/influx.js'

export default {
async fetch(request, env, ctx, { reportRequestMetrics = reportRequestMetricsToInflux } = {}) {
const response = await fetch(request)
ctx.waitUntil(reportRequestMetrics(request, env))
return response
},
}
66 changes: 0 additions & 66 deletions index.js

This file was deleted.

47 changes: 47 additions & 0 deletions lib/influx.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Reports request metrics to InfluxDB
* @param {Request} request - incoming request
* @param {object} env - environment variables
*/
export const reportRequestMetrics = async (request, env) => {
await writeMetrics(createMetricsFromRequest(request, env), env)
}

/*
* Returns request metrics in InfluxDB line protocol format
* https://docs.influxdata.com/influxdb/cloud/reference/syntax/line-protocol/
* @param {Request} request - incoming request
* @param {object} env - environment variables
*/
export const createMetricsFromRequest = (request, env) => {
const url = new URL(request.url);
const timestamp = Date.now();
const apiKey = request.headers.get('api-key') ||
url.searchParams.get('api-key') || (
request.headers.get('Authorization')?.startsWith('Bearer ')
? request.headers.get('Authorization').substring(7)
: 'unknown'
);

return `${env.INFLUX_METRIC_NAME} api_key="${apiKey}" ${timestamp}`
pyropy marked this conversation as resolved.
Show resolved Hide resolved
}

/*
* Sends request metrics to InfluxDB
* https://docs.influxdata.com/enterprise_influxdb/v1/guides/write_data/
* @param {string} lineProtocolData - InfluxDB line protocol formatted data
* @param {object} env - environment variables
*/
export const writeMetrics = async (lineProtocolData, env) => {
// Define API endpoint and headers
const url = `${env.INFLUX_URL}/api/v2/write?&bucket=${env.INFLUX_DATABASE}&precision=ms`;
bajtos marked this conversation as resolved.
Show resolved Hide resolved

return fetch(url, {
method: 'POST',
headers: {
'Authorization': `Token ${env.INFLUX_TOKEN}`,
'Content-Type': 'application/octet-stream'
},
body: lineProtocolData,
})
}
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
"main": "index.js",
"scripts": {
"deploy": "wrangler deploy",
"dev": "wrangler dev",
"deploy:prod": "wrangler deploy --env production",
"dev": "wrangler dev --env dev",
"start": "wrangler dev",
"test": "vitest"
"test": "vitest run",
"test:watch": "vitest"
},
"author": "vanadium23 <[email protected]>",
"license": "MIT",
Expand Down
Loading
Loading