Skip to content

Commit

Permalink
add honeycomb, some error catching to figure out whats happening (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
SathyaBhat committed May 12, 2024
1 parent 63bf70f commit e53efba
Show file tree
Hide file tree
Showing 8 changed files with 2,385 additions and 122 deletions.
5 changes: 5 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
YNAB_TOKEN=<token>
BUDGET_ID=<id>
LOG_LEVEL=debug
HONEYCOMB_API_KEY=<api key>
OTEL_SERVICE_NAME=my-ynab-exporter
29 changes: 26 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,23 @@
### ynab-exporter

A simple Prometheus exporter for [You Need A Budget](https://www.ynab.com)(YNAB) budgeting data.
A Prometheus exporter for [You Need A Budget](https://www.ynab.com)(YNAB) budgeting data. This exporter fetches data from YNAB API and publishes the following metrics

```
# HELP ynab_category_balance_amount Category Balance amount
# TYPE ynab_category_balance_amount gauge
# HELP ynab_category_activity_amount Category Activity amount
# TYPE ynab_category_activity_amount gauge
# HELP ynab_category_budgeted_amount Category Budgeted amount
# TYPE ynab_category_budgeted_amount gauge
# HELP ynab_cleared_account_balance Account Cleared Balance amounts
# TYPE ynab_cleared_account_balance gauge
# HELP ynab_uncleared_account_balance Account Uncleared Balance amounts
# TYPE ynab_uncleared_account_balance gauge
```

### How do I get started?

Expand All @@ -11,10 +28,16 @@ A simple Prometheus exporter for [You Need A Budget](https://www.ynab.com)(YNAB)
docker build . -t sathyabhat/ynab-exporter
```

- Export the following environment variables:
- Set the following environment variables:

* `YNAB_TOKEN` - API token from [YNAB](https://api.ynab.com/).
* `BUDGET_ID` - The id corresponding to your YNAB budget. Soon, this exporter will fetch and publish data from all budgets.

Optionally, to enable OTEL logging via [Honeycomb](https://www.honeycomb.io/)
* `HONEYCOMB_API_KEY` - Honeycomb API key
* `OTEL_SERVICE_NAME` - A custom name for your service.

A sample `.env` file is provided in [.env.example](./.env.sample).

- Run the exporter

Expand All @@ -26,4 +49,4 @@ The exporter will start listening on the port that you provide as a `PORT` envir

### Feedback/suggestions

If you have any feedback/suggestions, please [open a Github issue](https://github.com/SathyaBhat/ynab-exporter/issues/new).
If you have any feedback/suggestions, please [open a GitHub issue](https://github.com/SathyaBhat/ynab-exporter/issues/new).
2,426 changes: 2,315 additions & 111 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
},
"license": "MIT",
"dependencies": {
"@honeycombio/opentelemetry-node": "^0.7.2",
"@opentelemetry/auto-instrumentations-node": "^0.46.0",
"cron": "^2.4.3",
"dotenv": "^16.4.5",
"express": "^4.18.2",
Expand Down
1 change: 0 additions & 1 deletion src/collectors.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import log from 'loglevel';
import {Account, Category} from "ynab";
import * as metrics from './metrics';

Expand Down
23 changes: 17 additions & 6 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@



import {CronJob} from 'cron';
import dotenv from "dotenv";
import express, {Express, Request, Response} from 'express';
import log, {LogLevelDesc} from 'loglevel';
import 'source-map-support/register';
import {AccountsResponse, Category} from "ynab";

import {YnabAPI} from "./api";
import {YNABCollector} from "./collectors";
import {scheduledAccountBalanceUpdate, scheduledCategoryBalanceUpdate} from "./jobs/accounts";
import {registry} from './metrics';
import './tracing';

async function main() {
dotenv.config();
Expand All @@ -19,13 +19,24 @@ async function main() {
const app: Express = express();
const ynabCollector = new YNABCollector();
const budgetName = await ynab.getAccountName();
let accountBalance: AccountsResponse;
let catBalance: Category[];

new CronJob({
cronTime: "*/15 * * * *",
onTick: async () => {
log.info(`Refreshing YNAB data at ${new Date().toLocaleString()}...`);
const accountBalance = await scheduledAccountBalanceUpdate(ynab);
const catBalance = await scheduledCategoryBalanceUpdate(ynab);
try {
accountBalance = await scheduledAccountBalanceUpdate(ynab);
} catch (error) {
log.error('Could not refresh account balance due to', error);
}
try {
catBalance = await scheduledCategoryBalanceUpdate(ynab);
} catch (error) {
log.error('Could not refresh category balance due to', error);
}

ynabCollector.collectAccountBalanceMetrics(budgetName, accountBalance.data.accounts);
ynabCollector.collectCategoryBalanceMetrics(budgetName, catBalance);
},
Expand All @@ -48,5 +59,5 @@ if (require.main === module) {
const logLevel = (process.env.LOG_LEVEL) as LogLevelDesc || 'info';
log.setLevel(logLevel);
log.info('Starting YNAB Exporter 💰💸');
main();
main().catch(error => log.error('Ran into error', error));
}
2 changes: 1 addition & 1 deletion src/metrics.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Gauge, Registry, collectDefaultMetrics} from "prom-client";
import {Gauge, Registry} from "prom-client";

const catLabels = ['name', 'category_group_name', 'budgeted_amount', 'activity_amount', 'balance_amount', 'hidden', 'deleted', 'budget_name'];
const accountLabels = ['budget_name', 'account_name', 'type', 'closed'];
Expand Down
19 changes: 19 additions & 0 deletions src/tracing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Example filename: tracing.ts
import {NodeSDK} from '@opentelemetry/sdk-node';
import {HoneycombSDK} from '@honeycombio/opentelemetry-node';
import {getNodeAutoInstrumentations} from '@opentelemetry/auto-instrumentations-node';

// Uses environment variables named HONEYCOMB_API_KEY and OTEL_SERVICE_NAME
const sdk: NodeSDK = new HoneycombSDK({
instrumentations: [
getNodeAutoInstrumentations({
// We recommend disabling fs automatic instrumentation because
// it can be noisy and expensive during startup
'@opentelemetry/instrumentation-fs': {
enabled: false,
},
}),
],
});

sdk.start();

0 comments on commit e53efba

Please sign in to comment.