@wise-old-man/utils 3.3.12 → 3.3.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.cjs +0 -227
- package/dist/es/index.js +0 -227
- package/dist/es/index.mjs +0 -227
- package/package.json +1 -1
package/dist/cjs/index.cjs
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var axios = require('axios');
|
|
4
|
-
var prometheus = require('prom-client');
|
|
5
|
-
var zod = require('zod');
|
|
6
|
-
require('dotenv/config');
|
|
7
|
-
var fetchable = require('@attio/fetchable');
|
|
8
|
-
|
|
9
3
|
var config = {
|
|
10
4
|
defaultUserAgent: `WiseOldMan JS Client v${process.env.npm_package_version}`,
|
|
11
5
|
baseAPIUrl: 'https://api.wiseoldman.net/v2'
|
|
@@ -2067,226 +2061,6 @@ function getParentEfficiencyMetric(metric) {
|
|
|
2067
2061
|
return null;
|
|
2068
2062
|
}
|
|
2069
2063
|
|
|
2070
|
-
/**
|
|
2071
|
-
* This file has been created as a way to force any usage
|
|
2072
|
-
* of process.env to go through a dotenv.config first.
|
|
2073
|
-
*/
|
|
2074
|
-
/**
|
|
2075
|
-
* This ensures that an env var is required in prod but optional in dev/test.
|
|
2076
|
-
*/
|
|
2077
|
-
function prodOnly(varSchema) {
|
|
2078
|
-
if (process.env.NODE_ENV === 'production') {
|
|
2079
|
-
return varSchema;
|
|
2080
|
-
}
|
|
2081
|
-
return zod.z.optional(varSchema);
|
|
2082
|
-
}
|
|
2083
|
-
const envVariablesSchema = zod.z.object({
|
|
2084
|
-
// Prisma Database URL
|
|
2085
|
-
CORE_DATABASE_URL: zod.z.string().trim().min(1),
|
|
2086
|
-
// Redis Configs
|
|
2087
|
-
REDIS_HOST: zod.z.string().trim().min(1),
|
|
2088
|
-
REDIS_PORT: zod.z.coerce.number().positive().int(),
|
|
2089
|
-
// Node Environment
|
|
2090
|
-
NODE_ENV: zod.z.enum(['development', 'production', 'test']),
|
|
2091
|
-
// Port for the API to run on
|
|
2092
|
-
API_PORT: zod.z.optional(zod.z.coerce.number().positive().int()),
|
|
2093
|
-
// Admin Password (For mod+ operations)
|
|
2094
|
-
ADMIN_PASSWORD: prodOnly(zod.z.string().trim().min(1)),
|
|
2095
|
-
// Sentry (for error tracking)
|
|
2096
|
-
API_SENTRY_DSN: prodOnly(zod.z.string().trim().min(1)),
|
|
2097
|
-
// Patreon Token (to access their API)
|
|
2098
|
-
PATREON_BEARER_TOKEN: prodOnly(zod.z.string().trim().min(1)),
|
|
2099
|
-
// Discord Bot API URL (to send events to)
|
|
2100
|
-
DISCORD_BOT_API_URL: prodOnly(zod.z.string().trim().min(1).url()),
|
|
2101
|
-
// Our Prometheus metrics aggregator service URL
|
|
2102
|
-
PROMETHEUS_METRICS_SERVICE_URL: prodOnly(zod.z.string().trim().min(1).url()),
|
|
2103
|
-
// Discord Monitoring Webhooks
|
|
2104
|
-
DISCORD_PATREON_WEBHOOK_URL: prodOnly(zod.z.string().trim().min(1).url()),
|
|
2105
|
-
DISCORD_MONITORING_WEBHOOK_URL: prodOnly(zod.z.string().trim().min(1).url()),
|
|
2106
|
-
// Proxy Configs
|
|
2107
|
-
PROXY_LIST: prodOnly(zod.z.string().trim().min(1)),
|
|
2108
|
-
PROXY_USER: prodOnly(zod.z.string().trim().min(1)),
|
|
2109
|
-
PROXY_PASSWORD: prodOnly(zod.z.string().trim().min(1)),
|
|
2110
|
-
PROXY_PORT: prodOnly(zod.z.coerce.number().positive().int()),
|
|
2111
|
-
CPU_COUNT: prodOnly(zod.z.coerce.number().positive().int()),
|
|
2112
|
-
// Openai API Key
|
|
2113
|
-
OPENAI_API_KEY: prodOnly(zod.z.string().trim().min(1).startsWith('sk-'))
|
|
2114
|
-
});
|
|
2115
|
-
// This will load env vars from a .env file, type check them,and throw an error
|
|
2116
|
-
// (interrupting the process) if they're required and missing, or of an invalid type.
|
|
2117
|
-
try {
|
|
2118
|
-
envVariablesSchema.parse(process.env);
|
|
2119
|
-
}
|
|
2120
|
-
catch (error) {
|
|
2121
|
-
const errorPayload = JSON.stringify(error, null, 2);
|
|
2122
|
-
throw new Error(`Invalid environment variables. Please check env.ts for more info.\n${errorPayload}`);
|
|
2123
|
-
}
|
|
2124
|
-
function getThreadIndex() {
|
|
2125
|
-
if (process.env.pm_id === undefined) {
|
|
2126
|
-
return null;
|
|
2127
|
-
}
|
|
2128
|
-
return parseInt(process.env.pm_id, 10);
|
|
2129
|
-
}
|
|
2130
|
-
|
|
2131
|
-
class PrometheusService {
|
|
2132
|
-
constructor() {
|
|
2133
|
-
this.pushInterval = null;
|
|
2134
|
-
this.registry = new prometheus.Registry();
|
|
2135
|
-
this.registry.setDefaultLabels({ app: 'wise-old-man', threadIndex: getThreadIndex() });
|
|
2136
|
-
prometheus.collectDefaultMetrics({ register: this.registry });
|
|
2137
|
-
this.effectHistogram = new prometheus.Histogram({
|
|
2138
|
-
name: 'effect_duration_seconds',
|
|
2139
|
-
help: 'Duration of effects in microseconds',
|
|
2140
|
-
labelNames: ['effectName', 'status'],
|
|
2141
|
-
buckets: [0.1, 0.3, 0.5, 0.7, 1, 3, 5, 7, 10, 30]
|
|
2142
|
-
});
|
|
2143
|
-
this.httpHistogram = new prometheus.Histogram({
|
|
2144
|
-
name: 'http_request_duration_seconds',
|
|
2145
|
-
help: 'Duration of HTTP requests in microseconds',
|
|
2146
|
-
labelNames: ['method', 'route', 'status', 'userAgent'],
|
|
2147
|
-
buckets: [0.1, 0.3, 0.5, 0.7, 1, 3, 5, 7, 10, 30]
|
|
2148
|
-
});
|
|
2149
|
-
this.jobHistogram = new prometheus.Histogram({
|
|
2150
|
-
name: 'job_duration_seconds',
|
|
2151
|
-
help: 'Duration of jobs in microseconds',
|
|
2152
|
-
labelNames: ['jobName', 'status'],
|
|
2153
|
-
buckets: [0.1, 0.5, 1, 5, 10, 30, 60]
|
|
2154
|
-
});
|
|
2155
|
-
this.jobQueueGauge = new prometheus.Gauge({
|
|
2156
|
-
name: 'job_queue_size',
|
|
2157
|
-
help: 'Number of jobs in different states for each queue',
|
|
2158
|
-
labelNames: ['queueName', 'state']
|
|
2159
|
-
});
|
|
2160
|
-
this.eventCounter = new prometheus.Counter({
|
|
2161
|
-
name: 'event_counter',
|
|
2162
|
-
help: 'Count of events emitted',
|
|
2163
|
-
labelNames: ['eventType']
|
|
2164
|
-
});
|
|
2165
|
-
this.customPeriodCounter = new prometheus.Counter({
|
|
2166
|
-
name: 'custom_period_counter',
|
|
2167
|
-
help: 'Count of custom period expressions used',
|
|
2168
|
-
labelNames: ['customPeriod']
|
|
2169
|
-
});
|
|
2170
|
-
this.updatePlayerJobSourceCounter = new prometheus.Counter({
|
|
2171
|
-
name: 'update_player_job_source_counter',
|
|
2172
|
-
help: 'Count of update player jobs dispatched',
|
|
2173
|
-
labelNames: ['source']
|
|
2174
|
-
});
|
|
2175
|
-
this.runeMetricsHistogram = new prometheus.Histogram({
|
|
2176
|
-
name: 'runemetrics_duration_seconds',
|
|
2177
|
-
help: 'Duration of RuneMetrics requests in microseconds',
|
|
2178
|
-
labelNames: ['status'],
|
|
2179
|
-
buckets: [0.1, 0.3, 0.5, 1, 5, 10, 30]
|
|
2180
|
-
});
|
|
2181
|
-
this.hiscoresHistogram = new prometheus.Histogram({
|
|
2182
|
-
name: 'hiscores_duration_seconds',
|
|
2183
|
-
help: 'Duration of hiscores requests in microseconds',
|
|
2184
|
-
labelNames: ['status'],
|
|
2185
|
-
buckets: [0.1, 0.3, 0.5, 1, 5, 10, 30]
|
|
2186
|
-
});
|
|
2187
|
-
this.registry.registerMetric(this.jobHistogram);
|
|
2188
|
-
this.registry.registerMetric(this.jobQueueGauge);
|
|
2189
|
-
this.registry.registerMetric(this.httpHistogram);
|
|
2190
|
-
this.registry.registerMetric(this.effectHistogram);
|
|
2191
|
-
this.registry.registerMetric(this.eventCounter);
|
|
2192
|
-
this.registry.registerMetric(this.customPeriodCounter);
|
|
2193
|
-
this.registry.registerMetric(this.updatePlayerJobSourceCounter);
|
|
2194
|
-
this.registry.registerMetric(this.runeMetricsHistogram);
|
|
2195
|
-
this.registry.registerMetric(this.hiscoresHistogram);
|
|
2196
|
-
}
|
|
2197
|
-
init() {
|
|
2198
|
-
this.pushInterval = setInterval(() => {
|
|
2199
|
-
this.pushMetrics();
|
|
2200
|
-
}, 60000);
|
|
2201
|
-
}
|
|
2202
|
-
shutdown() {
|
|
2203
|
-
if (this.pushInterval !== null) {
|
|
2204
|
-
clearInterval(this.pushInterval);
|
|
2205
|
-
}
|
|
2206
|
-
}
|
|
2207
|
-
pushMetrics() {
|
|
2208
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
2209
|
-
if (process.env.NODE_ENV === 'test') {
|
|
2210
|
-
return fetchable.errored({ code: 'NOT_ALLOWED_IN_TEST_ENV' });
|
|
2211
|
-
}
|
|
2212
|
-
if (!process.env.PROMETHEUS_METRICS_SERVICE_URL) {
|
|
2213
|
-
return fetchable.errored({ code: 'MISSING_METRICS_URL' });
|
|
2214
|
-
}
|
|
2215
|
-
const metricsResult = yield fetchable.fromPromise(this.registry.getMetricsAsJSON());
|
|
2216
|
-
if (fetchable.isErrored(metricsResult)) {
|
|
2217
|
-
return fetchable.errored({
|
|
2218
|
-
code: 'FAILED_TO_GET_PROMETHEUS_METRICS',
|
|
2219
|
-
subError: metricsResult.error
|
|
2220
|
-
});
|
|
2221
|
-
}
|
|
2222
|
-
const requestResult = yield fetchable.fromPromise(axios.post(process.env.PROMETHEUS_METRICS_SERVICE_URL, {
|
|
2223
|
-
source: 'api',
|
|
2224
|
-
data: metricsResult.value,
|
|
2225
|
-
threadIndex: getThreadIndex()
|
|
2226
|
-
}));
|
|
2227
|
-
if (fetchable.isErrored(requestResult)) {
|
|
2228
|
-
return fetchable.errored({
|
|
2229
|
-
code: 'FAILED_TO_PUSH_PROMETHEUS_METRICS',
|
|
2230
|
-
subError: requestResult.error
|
|
2231
|
-
});
|
|
2232
|
-
}
|
|
2233
|
-
return fetchable.complete(true);
|
|
2234
|
-
});
|
|
2235
|
-
}
|
|
2236
|
-
trackHttpRequest() {
|
|
2237
|
-
return this.httpHistogram.startTimer();
|
|
2238
|
-
}
|
|
2239
|
-
trackRuneMetricsRequest() {
|
|
2240
|
-
return this.runeMetricsHistogram.startTimer();
|
|
2241
|
-
}
|
|
2242
|
-
trackHiscoresRequest() {
|
|
2243
|
-
return this.hiscoresHistogram.startTimer();
|
|
2244
|
-
}
|
|
2245
|
-
trackEffect(effectName, fn) {
|
|
2246
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
2247
|
-
const endTimer = this.effectHistogram.startTimer();
|
|
2248
|
-
try {
|
|
2249
|
-
yield fn();
|
|
2250
|
-
endTimer({ effectName, status: 1 });
|
|
2251
|
-
}
|
|
2252
|
-
catch (error) {
|
|
2253
|
-
endTimer({ effectName, status: 0 });
|
|
2254
|
-
throw error;
|
|
2255
|
-
}
|
|
2256
|
-
});
|
|
2257
|
-
}
|
|
2258
|
-
trackJob(jobName, handler) {
|
|
2259
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
2260
|
-
const endTimer = this.jobHistogram.startTimer();
|
|
2261
|
-
try {
|
|
2262
|
-
yield handler();
|
|
2263
|
-
endTimer({ jobName, status: 1 });
|
|
2264
|
-
}
|
|
2265
|
-
catch (error) {
|
|
2266
|
-
endTimer({ jobName, status: 0 });
|
|
2267
|
-
throw error;
|
|
2268
|
-
}
|
|
2269
|
-
});
|
|
2270
|
-
}
|
|
2271
|
-
trackEventEmitted(eventType) {
|
|
2272
|
-
this.eventCounter.inc({ eventType });
|
|
2273
|
-
}
|
|
2274
|
-
trackCustomPeriodExpression(customPeriod) {
|
|
2275
|
-
this.customPeriodCounter.inc({ customPeriod });
|
|
2276
|
-
}
|
|
2277
|
-
trackUpdatePlayerJobSource(source) {
|
|
2278
|
-
this.updatePlayerJobSourceCounter.inc({ source });
|
|
2279
|
-
}
|
|
2280
|
-
updateQueueMetrics(queueName, counts) {
|
|
2281
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
2282
|
-
for (const [state, count] of Object.entries(counts)) {
|
|
2283
|
-
this.jobQueueGauge.set({ queueName, state }, count);
|
|
2284
|
-
}
|
|
2285
|
-
});
|
|
2286
|
-
}
|
|
2287
|
-
}
|
|
2288
|
-
var prometheusService = new PrometheusService();
|
|
2289
|
-
|
|
2290
2064
|
const CUSTOM_PERIOD_REGEX = /(\d+y)?(\d+m)?(\d+w)?(\d+d)?(\d+h)?/;
|
|
2291
2065
|
const PeriodProps = {
|
|
2292
2066
|
[Period.FIVE_MIN]: { name: '5 Min', milliseconds: 300000 },
|
|
@@ -2314,7 +2088,6 @@ function parsePeriodExpression(periodExpression) {
|
|
|
2314
2088
|
durationMs: PeriodProps[fixed].milliseconds
|
|
2315
2089
|
};
|
|
2316
2090
|
}
|
|
2317
|
-
prometheusService.trackCustomPeriodExpression(fixed);
|
|
2318
2091
|
const result = fixed.match(CUSTOM_PERIOD_REGEX);
|
|
2319
2092
|
if (!result || result.length === 0 || result[0] !== fixed)
|
|
2320
2093
|
return null;
|
package/dist/es/index.js
CHANGED
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import axios from 'axios';
|
|
2
|
-
import prometheus from 'prom-client';
|
|
3
|
-
import { z } from 'zod';
|
|
4
|
-
import 'dotenv/config';
|
|
5
|
-
import { errored, fromPromise, isErrored, complete } from '@attio/fetchable';
|
|
6
|
-
|
|
7
1
|
var config = {
|
|
8
2
|
defaultUserAgent: `WiseOldMan JS Client v${process.env.npm_package_version}`,
|
|
9
3
|
baseAPIUrl: 'https://api.wiseoldman.net/v2'
|
|
@@ -2065,226 +2059,6 @@ function getParentEfficiencyMetric(metric) {
|
|
|
2065
2059
|
return null;
|
|
2066
2060
|
}
|
|
2067
2061
|
|
|
2068
|
-
/**
|
|
2069
|
-
* This file has been created as a way to force any usage
|
|
2070
|
-
* of process.env to go through a dotenv.config first.
|
|
2071
|
-
*/
|
|
2072
|
-
/**
|
|
2073
|
-
* This ensures that an env var is required in prod but optional in dev/test.
|
|
2074
|
-
*/
|
|
2075
|
-
function prodOnly(varSchema) {
|
|
2076
|
-
if (process.env.NODE_ENV === 'production') {
|
|
2077
|
-
return varSchema;
|
|
2078
|
-
}
|
|
2079
|
-
return z.optional(varSchema);
|
|
2080
|
-
}
|
|
2081
|
-
const envVariablesSchema = z.object({
|
|
2082
|
-
// Prisma Database URL
|
|
2083
|
-
CORE_DATABASE_URL: z.string().trim().min(1),
|
|
2084
|
-
// Redis Configs
|
|
2085
|
-
REDIS_HOST: z.string().trim().min(1),
|
|
2086
|
-
REDIS_PORT: z.coerce.number().positive().int(),
|
|
2087
|
-
// Node Environment
|
|
2088
|
-
NODE_ENV: z.enum(['development', 'production', 'test']),
|
|
2089
|
-
// Port for the API to run on
|
|
2090
|
-
API_PORT: z.optional(z.coerce.number().positive().int()),
|
|
2091
|
-
// Admin Password (For mod+ operations)
|
|
2092
|
-
ADMIN_PASSWORD: prodOnly(z.string().trim().min(1)),
|
|
2093
|
-
// Sentry (for error tracking)
|
|
2094
|
-
API_SENTRY_DSN: prodOnly(z.string().trim().min(1)),
|
|
2095
|
-
// Patreon Token (to access their API)
|
|
2096
|
-
PATREON_BEARER_TOKEN: prodOnly(z.string().trim().min(1)),
|
|
2097
|
-
// Discord Bot API URL (to send events to)
|
|
2098
|
-
DISCORD_BOT_API_URL: prodOnly(z.string().trim().min(1).url()),
|
|
2099
|
-
// Our Prometheus metrics aggregator service URL
|
|
2100
|
-
PROMETHEUS_METRICS_SERVICE_URL: prodOnly(z.string().trim().min(1).url()),
|
|
2101
|
-
// Discord Monitoring Webhooks
|
|
2102
|
-
DISCORD_PATREON_WEBHOOK_URL: prodOnly(z.string().trim().min(1).url()),
|
|
2103
|
-
DISCORD_MONITORING_WEBHOOK_URL: prodOnly(z.string().trim().min(1).url()),
|
|
2104
|
-
// Proxy Configs
|
|
2105
|
-
PROXY_LIST: prodOnly(z.string().trim().min(1)),
|
|
2106
|
-
PROXY_USER: prodOnly(z.string().trim().min(1)),
|
|
2107
|
-
PROXY_PASSWORD: prodOnly(z.string().trim().min(1)),
|
|
2108
|
-
PROXY_PORT: prodOnly(z.coerce.number().positive().int()),
|
|
2109
|
-
CPU_COUNT: prodOnly(z.coerce.number().positive().int()),
|
|
2110
|
-
// Openai API Key
|
|
2111
|
-
OPENAI_API_KEY: prodOnly(z.string().trim().min(1).startsWith('sk-'))
|
|
2112
|
-
});
|
|
2113
|
-
// This will load env vars from a .env file, type check them,and throw an error
|
|
2114
|
-
// (interrupting the process) if they're required and missing, or of an invalid type.
|
|
2115
|
-
try {
|
|
2116
|
-
envVariablesSchema.parse(process.env);
|
|
2117
|
-
}
|
|
2118
|
-
catch (error) {
|
|
2119
|
-
const errorPayload = JSON.stringify(error, null, 2);
|
|
2120
|
-
throw new Error(`Invalid environment variables. Please check env.ts for more info.\n${errorPayload}`);
|
|
2121
|
-
}
|
|
2122
|
-
function getThreadIndex() {
|
|
2123
|
-
if (process.env.pm_id === undefined) {
|
|
2124
|
-
return null;
|
|
2125
|
-
}
|
|
2126
|
-
return parseInt(process.env.pm_id, 10);
|
|
2127
|
-
}
|
|
2128
|
-
|
|
2129
|
-
class PrometheusService {
|
|
2130
|
-
constructor() {
|
|
2131
|
-
this.pushInterval = null;
|
|
2132
|
-
this.registry = new prometheus.Registry();
|
|
2133
|
-
this.registry.setDefaultLabels({ app: 'wise-old-man', threadIndex: getThreadIndex() });
|
|
2134
|
-
prometheus.collectDefaultMetrics({ register: this.registry });
|
|
2135
|
-
this.effectHistogram = new prometheus.Histogram({
|
|
2136
|
-
name: 'effect_duration_seconds',
|
|
2137
|
-
help: 'Duration of effects in microseconds',
|
|
2138
|
-
labelNames: ['effectName', 'status'],
|
|
2139
|
-
buckets: [0.1, 0.3, 0.5, 0.7, 1, 3, 5, 7, 10, 30]
|
|
2140
|
-
});
|
|
2141
|
-
this.httpHistogram = new prometheus.Histogram({
|
|
2142
|
-
name: 'http_request_duration_seconds',
|
|
2143
|
-
help: 'Duration of HTTP requests in microseconds',
|
|
2144
|
-
labelNames: ['method', 'route', 'status', 'userAgent'],
|
|
2145
|
-
buckets: [0.1, 0.3, 0.5, 0.7, 1, 3, 5, 7, 10, 30]
|
|
2146
|
-
});
|
|
2147
|
-
this.jobHistogram = new prometheus.Histogram({
|
|
2148
|
-
name: 'job_duration_seconds',
|
|
2149
|
-
help: 'Duration of jobs in microseconds',
|
|
2150
|
-
labelNames: ['jobName', 'status'],
|
|
2151
|
-
buckets: [0.1, 0.5, 1, 5, 10, 30, 60]
|
|
2152
|
-
});
|
|
2153
|
-
this.jobQueueGauge = new prometheus.Gauge({
|
|
2154
|
-
name: 'job_queue_size',
|
|
2155
|
-
help: 'Number of jobs in different states for each queue',
|
|
2156
|
-
labelNames: ['queueName', 'state']
|
|
2157
|
-
});
|
|
2158
|
-
this.eventCounter = new prometheus.Counter({
|
|
2159
|
-
name: 'event_counter',
|
|
2160
|
-
help: 'Count of events emitted',
|
|
2161
|
-
labelNames: ['eventType']
|
|
2162
|
-
});
|
|
2163
|
-
this.customPeriodCounter = new prometheus.Counter({
|
|
2164
|
-
name: 'custom_period_counter',
|
|
2165
|
-
help: 'Count of custom period expressions used',
|
|
2166
|
-
labelNames: ['customPeriod']
|
|
2167
|
-
});
|
|
2168
|
-
this.updatePlayerJobSourceCounter = new prometheus.Counter({
|
|
2169
|
-
name: 'update_player_job_source_counter',
|
|
2170
|
-
help: 'Count of update player jobs dispatched',
|
|
2171
|
-
labelNames: ['source']
|
|
2172
|
-
});
|
|
2173
|
-
this.runeMetricsHistogram = new prometheus.Histogram({
|
|
2174
|
-
name: 'runemetrics_duration_seconds',
|
|
2175
|
-
help: 'Duration of RuneMetrics requests in microseconds',
|
|
2176
|
-
labelNames: ['status'],
|
|
2177
|
-
buckets: [0.1, 0.3, 0.5, 1, 5, 10, 30]
|
|
2178
|
-
});
|
|
2179
|
-
this.hiscoresHistogram = new prometheus.Histogram({
|
|
2180
|
-
name: 'hiscores_duration_seconds',
|
|
2181
|
-
help: 'Duration of hiscores requests in microseconds',
|
|
2182
|
-
labelNames: ['status'],
|
|
2183
|
-
buckets: [0.1, 0.3, 0.5, 1, 5, 10, 30]
|
|
2184
|
-
});
|
|
2185
|
-
this.registry.registerMetric(this.jobHistogram);
|
|
2186
|
-
this.registry.registerMetric(this.jobQueueGauge);
|
|
2187
|
-
this.registry.registerMetric(this.httpHistogram);
|
|
2188
|
-
this.registry.registerMetric(this.effectHistogram);
|
|
2189
|
-
this.registry.registerMetric(this.eventCounter);
|
|
2190
|
-
this.registry.registerMetric(this.customPeriodCounter);
|
|
2191
|
-
this.registry.registerMetric(this.updatePlayerJobSourceCounter);
|
|
2192
|
-
this.registry.registerMetric(this.runeMetricsHistogram);
|
|
2193
|
-
this.registry.registerMetric(this.hiscoresHistogram);
|
|
2194
|
-
}
|
|
2195
|
-
init() {
|
|
2196
|
-
this.pushInterval = setInterval(() => {
|
|
2197
|
-
this.pushMetrics();
|
|
2198
|
-
}, 60000);
|
|
2199
|
-
}
|
|
2200
|
-
shutdown() {
|
|
2201
|
-
if (this.pushInterval !== null) {
|
|
2202
|
-
clearInterval(this.pushInterval);
|
|
2203
|
-
}
|
|
2204
|
-
}
|
|
2205
|
-
pushMetrics() {
|
|
2206
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
2207
|
-
if (process.env.NODE_ENV === 'test') {
|
|
2208
|
-
return errored({ code: 'NOT_ALLOWED_IN_TEST_ENV' });
|
|
2209
|
-
}
|
|
2210
|
-
if (!process.env.PROMETHEUS_METRICS_SERVICE_URL) {
|
|
2211
|
-
return errored({ code: 'MISSING_METRICS_URL' });
|
|
2212
|
-
}
|
|
2213
|
-
const metricsResult = yield fromPromise(this.registry.getMetricsAsJSON());
|
|
2214
|
-
if (isErrored(metricsResult)) {
|
|
2215
|
-
return errored({
|
|
2216
|
-
code: 'FAILED_TO_GET_PROMETHEUS_METRICS',
|
|
2217
|
-
subError: metricsResult.error
|
|
2218
|
-
});
|
|
2219
|
-
}
|
|
2220
|
-
const requestResult = yield fromPromise(axios.post(process.env.PROMETHEUS_METRICS_SERVICE_URL, {
|
|
2221
|
-
source: 'api',
|
|
2222
|
-
data: metricsResult.value,
|
|
2223
|
-
threadIndex: getThreadIndex()
|
|
2224
|
-
}));
|
|
2225
|
-
if (isErrored(requestResult)) {
|
|
2226
|
-
return errored({
|
|
2227
|
-
code: 'FAILED_TO_PUSH_PROMETHEUS_METRICS',
|
|
2228
|
-
subError: requestResult.error
|
|
2229
|
-
});
|
|
2230
|
-
}
|
|
2231
|
-
return complete(true);
|
|
2232
|
-
});
|
|
2233
|
-
}
|
|
2234
|
-
trackHttpRequest() {
|
|
2235
|
-
return this.httpHistogram.startTimer();
|
|
2236
|
-
}
|
|
2237
|
-
trackRuneMetricsRequest() {
|
|
2238
|
-
return this.runeMetricsHistogram.startTimer();
|
|
2239
|
-
}
|
|
2240
|
-
trackHiscoresRequest() {
|
|
2241
|
-
return this.hiscoresHistogram.startTimer();
|
|
2242
|
-
}
|
|
2243
|
-
trackEffect(effectName, fn) {
|
|
2244
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
2245
|
-
const endTimer = this.effectHistogram.startTimer();
|
|
2246
|
-
try {
|
|
2247
|
-
yield fn();
|
|
2248
|
-
endTimer({ effectName, status: 1 });
|
|
2249
|
-
}
|
|
2250
|
-
catch (error) {
|
|
2251
|
-
endTimer({ effectName, status: 0 });
|
|
2252
|
-
throw error;
|
|
2253
|
-
}
|
|
2254
|
-
});
|
|
2255
|
-
}
|
|
2256
|
-
trackJob(jobName, handler) {
|
|
2257
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
2258
|
-
const endTimer = this.jobHistogram.startTimer();
|
|
2259
|
-
try {
|
|
2260
|
-
yield handler();
|
|
2261
|
-
endTimer({ jobName, status: 1 });
|
|
2262
|
-
}
|
|
2263
|
-
catch (error) {
|
|
2264
|
-
endTimer({ jobName, status: 0 });
|
|
2265
|
-
throw error;
|
|
2266
|
-
}
|
|
2267
|
-
});
|
|
2268
|
-
}
|
|
2269
|
-
trackEventEmitted(eventType) {
|
|
2270
|
-
this.eventCounter.inc({ eventType });
|
|
2271
|
-
}
|
|
2272
|
-
trackCustomPeriodExpression(customPeriod) {
|
|
2273
|
-
this.customPeriodCounter.inc({ customPeriod });
|
|
2274
|
-
}
|
|
2275
|
-
trackUpdatePlayerJobSource(source) {
|
|
2276
|
-
this.updatePlayerJobSourceCounter.inc({ source });
|
|
2277
|
-
}
|
|
2278
|
-
updateQueueMetrics(queueName, counts) {
|
|
2279
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
2280
|
-
for (const [state, count] of Object.entries(counts)) {
|
|
2281
|
-
this.jobQueueGauge.set({ queueName, state }, count);
|
|
2282
|
-
}
|
|
2283
|
-
});
|
|
2284
|
-
}
|
|
2285
|
-
}
|
|
2286
|
-
var prometheusService = new PrometheusService();
|
|
2287
|
-
|
|
2288
2062
|
const CUSTOM_PERIOD_REGEX = /(\d+y)?(\d+m)?(\d+w)?(\d+d)?(\d+h)?/;
|
|
2289
2063
|
const PeriodProps = {
|
|
2290
2064
|
[Period.FIVE_MIN]: { name: '5 Min', milliseconds: 300000 },
|
|
@@ -2312,7 +2086,6 @@ function parsePeriodExpression(periodExpression) {
|
|
|
2312
2086
|
durationMs: PeriodProps[fixed].milliseconds
|
|
2313
2087
|
};
|
|
2314
2088
|
}
|
|
2315
|
-
prometheusService.trackCustomPeriodExpression(fixed);
|
|
2316
2089
|
const result = fixed.match(CUSTOM_PERIOD_REGEX);
|
|
2317
2090
|
if (!result || result.length === 0 || result[0] !== fixed)
|
|
2318
2091
|
return null;
|
package/dist/es/index.mjs
CHANGED
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import axios from 'axios';
|
|
2
|
-
import prometheus from 'prom-client';
|
|
3
|
-
import { z } from 'zod';
|
|
4
|
-
import 'dotenv/config';
|
|
5
|
-
import { errored, fromPromise, isErrored, complete } from '@attio/fetchable';
|
|
6
|
-
|
|
7
1
|
var config = {
|
|
8
2
|
defaultUserAgent: `WiseOldMan JS Client v${process.env.npm_package_version}`,
|
|
9
3
|
baseAPIUrl: 'https://api.wiseoldman.net/v2'
|
|
@@ -2065,226 +2059,6 @@ function getParentEfficiencyMetric(metric) {
|
|
|
2065
2059
|
return null;
|
|
2066
2060
|
}
|
|
2067
2061
|
|
|
2068
|
-
/**
|
|
2069
|
-
* This file has been created as a way to force any usage
|
|
2070
|
-
* of process.env to go through a dotenv.config first.
|
|
2071
|
-
*/
|
|
2072
|
-
/**
|
|
2073
|
-
* This ensures that an env var is required in prod but optional in dev/test.
|
|
2074
|
-
*/
|
|
2075
|
-
function prodOnly(varSchema) {
|
|
2076
|
-
if (process.env.NODE_ENV === 'production') {
|
|
2077
|
-
return varSchema;
|
|
2078
|
-
}
|
|
2079
|
-
return z.optional(varSchema);
|
|
2080
|
-
}
|
|
2081
|
-
const envVariablesSchema = z.object({
|
|
2082
|
-
// Prisma Database URL
|
|
2083
|
-
CORE_DATABASE_URL: z.string().trim().min(1),
|
|
2084
|
-
// Redis Configs
|
|
2085
|
-
REDIS_HOST: z.string().trim().min(1),
|
|
2086
|
-
REDIS_PORT: z.coerce.number().positive().int(),
|
|
2087
|
-
// Node Environment
|
|
2088
|
-
NODE_ENV: z.enum(['development', 'production', 'test']),
|
|
2089
|
-
// Port for the API to run on
|
|
2090
|
-
API_PORT: z.optional(z.coerce.number().positive().int()),
|
|
2091
|
-
// Admin Password (For mod+ operations)
|
|
2092
|
-
ADMIN_PASSWORD: prodOnly(z.string().trim().min(1)),
|
|
2093
|
-
// Sentry (for error tracking)
|
|
2094
|
-
API_SENTRY_DSN: prodOnly(z.string().trim().min(1)),
|
|
2095
|
-
// Patreon Token (to access their API)
|
|
2096
|
-
PATREON_BEARER_TOKEN: prodOnly(z.string().trim().min(1)),
|
|
2097
|
-
// Discord Bot API URL (to send events to)
|
|
2098
|
-
DISCORD_BOT_API_URL: prodOnly(z.string().trim().min(1).url()),
|
|
2099
|
-
// Our Prometheus metrics aggregator service URL
|
|
2100
|
-
PROMETHEUS_METRICS_SERVICE_URL: prodOnly(z.string().trim().min(1).url()),
|
|
2101
|
-
// Discord Monitoring Webhooks
|
|
2102
|
-
DISCORD_PATREON_WEBHOOK_URL: prodOnly(z.string().trim().min(1).url()),
|
|
2103
|
-
DISCORD_MONITORING_WEBHOOK_URL: prodOnly(z.string().trim().min(1).url()),
|
|
2104
|
-
// Proxy Configs
|
|
2105
|
-
PROXY_LIST: prodOnly(z.string().trim().min(1)),
|
|
2106
|
-
PROXY_USER: prodOnly(z.string().trim().min(1)),
|
|
2107
|
-
PROXY_PASSWORD: prodOnly(z.string().trim().min(1)),
|
|
2108
|
-
PROXY_PORT: prodOnly(z.coerce.number().positive().int()),
|
|
2109
|
-
CPU_COUNT: prodOnly(z.coerce.number().positive().int()),
|
|
2110
|
-
// Openai API Key
|
|
2111
|
-
OPENAI_API_KEY: prodOnly(z.string().trim().min(1).startsWith('sk-'))
|
|
2112
|
-
});
|
|
2113
|
-
// This will load env vars from a .env file, type check them,and throw an error
|
|
2114
|
-
// (interrupting the process) if they're required and missing, or of an invalid type.
|
|
2115
|
-
try {
|
|
2116
|
-
envVariablesSchema.parse(process.env);
|
|
2117
|
-
}
|
|
2118
|
-
catch (error) {
|
|
2119
|
-
const errorPayload = JSON.stringify(error, null, 2);
|
|
2120
|
-
throw new Error(`Invalid environment variables. Please check env.ts for more info.\n${errorPayload}`);
|
|
2121
|
-
}
|
|
2122
|
-
function getThreadIndex() {
|
|
2123
|
-
if (process.env.pm_id === undefined) {
|
|
2124
|
-
return null;
|
|
2125
|
-
}
|
|
2126
|
-
return parseInt(process.env.pm_id, 10);
|
|
2127
|
-
}
|
|
2128
|
-
|
|
2129
|
-
class PrometheusService {
|
|
2130
|
-
constructor() {
|
|
2131
|
-
this.pushInterval = null;
|
|
2132
|
-
this.registry = new prometheus.Registry();
|
|
2133
|
-
this.registry.setDefaultLabels({ app: 'wise-old-man', threadIndex: getThreadIndex() });
|
|
2134
|
-
prometheus.collectDefaultMetrics({ register: this.registry });
|
|
2135
|
-
this.effectHistogram = new prometheus.Histogram({
|
|
2136
|
-
name: 'effect_duration_seconds',
|
|
2137
|
-
help: 'Duration of effects in microseconds',
|
|
2138
|
-
labelNames: ['effectName', 'status'],
|
|
2139
|
-
buckets: [0.1, 0.3, 0.5, 0.7, 1, 3, 5, 7, 10, 30]
|
|
2140
|
-
});
|
|
2141
|
-
this.httpHistogram = new prometheus.Histogram({
|
|
2142
|
-
name: 'http_request_duration_seconds',
|
|
2143
|
-
help: 'Duration of HTTP requests in microseconds',
|
|
2144
|
-
labelNames: ['method', 'route', 'status', 'userAgent'],
|
|
2145
|
-
buckets: [0.1, 0.3, 0.5, 0.7, 1, 3, 5, 7, 10, 30]
|
|
2146
|
-
});
|
|
2147
|
-
this.jobHistogram = new prometheus.Histogram({
|
|
2148
|
-
name: 'job_duration_seconds',
|
|
2149
|
-
help: 'Duration of jobs in microseconds',
|
|
2150
|
-
labelNames: ['jobName', 'status'],
|
|
2151
|
-
buckets: [0.1, 0.5, 1, 5, 10, 30, 60]
|
|
2152
|
-
});
|
|
2153
|
-
this.jobQueueGauge = new prometheus.Gauge({
|
|
2154
|
-
name: 'job_queue_size',
|
|
2155
|
-
help: 'Number of jobs in different states for each queue',
|
|
2156
|
-
labelNames: ['queueName', 'state']
|
|
2157
|
-
});
|
|
2158
|
-
this.eventCounter = new prometheus.Counter({
|
|
2159
|
-
name: 'event_counter',
|
|
2160
|
-
help: 'Count of events emitted',
|
|
2161
|
-
labelNames: ['eventType']
|
|
2162
|
-
});
|
|
2163
|
-
this.customPeriodCounter = new prometheus.Counter({
|
|
2164
|
-
name: 'custom_period_counter',
|
|
2165
|
-
help: 'Count of custom period expressions used',
|
|
2166
|
-
labelNames: ['customPeriod']
|
|
2167
|
-
});
|
|
2168
|
-
this.updatePlayerJobSourceCounter = new prometheus.Counter({
|
|
2169
|
-
name: 'update_player_job_source_counter',
|
|
2170
|
-
help: 'Count of update player jobs dispatched',
|
|
2171
|
-
labelNames: ['source']
|
|
2172
|
-
});
|
|
2173
|
-
this.runeMetricsHistogram = new prometheus.Histogram({
|
|
2174
|
-
name: 'runemetrics_duration_seconds',
|
|
2175
|
-
help: 'Duration of RuneMetrics requests in microseconds',
|
|
2176
|
-
labelNames: ['status'],
|
|
2177
|
-
buckets: [0.1, 0.3, 0.5, 1, 5, 10, 30]
|
|
2178
|
-
});
|
|
2179
|
-
this.hiscoresHistogram = new prometheus.Histogram({
|
|
2180
|
-
name: 'hiscores_duration_seconds',
|
|
2181
|
-
help: 'Duration of hiscores requests in microseconds',
|
|
2182
|
-
labelNames: ['status'],
|
|
2183
|
-
buckets: [0.1, 0.3, 0.5, 1, 5, 10, 30]
|
|
2184
|
-
});
|
|
2185
|
-
this.registry.registerMetric(this.jobHistogram);
|
|
2186
|
-
this.registry.registerMetric(this.jobQueueGauge);
|
|
2187
|
-
this.registry.registerMetric(this.httpHistogram);
|
|
2188
|
-
this.registry.registerMetric(this.effectHistogram);
|
|
2189
|
-
this.registry.registerMetric(this.eventCounter);
|
|
2190
|
-
this.registry.registerMetric(this.customPeriodCounter);
|
|
2191
|
-
this.registry.registerMetric(this.updatePlayerJobSourceCounter);
|
|
2192
|
-
this.registry.registerMetric(this.runeMetricsHistogram);
|
|
2193
|
-
this.registry.registerMetric(this.hiscoresHistogram);
|
|
2194
|
-
}
|
|
2195
|
-
init() {
|
|
2196
|
-
this.pushInterval = setInterval(() => {
|
|
2197
|
-
this.pushMetrics();
|
|
2198
|
-
}, 60000);
|
|
2199
|
-
}
|
|
2200
|
-
shutdown() {
|
|
2201
|
-
if (this.pushInterval !== null) {
|
|
2202
|
-
clearInterval(this.pushInterval);
|
|
2203
|
-
}
|
|
2204
|
-
}
|
|
2205
|
-
pushMetrics() {
|
|
2206
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
2207
|
-
if (process.env.NODE_ENV === 'test') {
|
|
2208
|
-
return errored({ code: 'NOT_ALLOWED_IN_TEST_ENV' });
|
|
2209
|
-
}
|
|
2210
|
-
if (!process.env.PROMETHEUS_METRICS_SERVICE_URL) {
|
|
2211
|
-
return errored({ code: 'MISSING_METRICS_URL' });
|
|
2212
|
-
}
|
|
2213
|
-
const metricsResult = yield fromPromise(this.registry.getMetricsAsJSON());
|
|
2214
|
-
if (isErrored(metricsResult)) {
|
|
2215
|
-
return errored({
|
|
2216
|
-
code: 'FAILED_TO_GET_PROMETHEUS_METRICS',
|
|
2217
|
-
subError: metricsResult.error
|
|
2218
|
-
});
|
|
2219
|
-
}
|
|
2220
|
-
const requestResult = yield fromPromise(axios.post(process.env.PROMETHEUS_METRICS_SERVICE_URL, {
|
|
2221
|
-
source: 'api',
|
|
2222
|
-
data: metricsResult.value,
|
|
2223
|
-
threadIndex: getThreadIndex()
|
|
2224
|
-
}));
|
|
2225
|
-
if (isErrored(requestResult)) {
|
|
2226
|
-
return errored({
|
|
2227
|
-
code: 'FAILED_TO_PUSH_PROMETHEUS_METRICS',
|
|
2228
|
-
subError: requestResult.error
|
|
2229
|
-
});
|
|
2230
|
-
}
|
|
2231
|
-
return complete(true);
|
|
2232
|
-
});
|
|
2233
|
-
}
|
|
2234
|
-
trackHttpRequest() {
|
|
2235
|
-
return this.httpHistogram.startTimer();
|
|
2236
|
-
}
|
|
2237
|
-
trackRuneMetricsRequest() {
|
|
2238
|
-
return this.runeMetricsHistogram.startTimer();
|
|
2239
|
-
}
|
|
2240
|
-
trackHiscoresRequest() {
|
|
2241
|
-
return this.hiscoresHistogram.startTimer();
|
|
2242
|
-
}
|
|
2243
|
-
trackEffect(effectName, fn) {
|
|
2244
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
2245
|
-
const endTimer = this.effectHistogram.startTimer();
|
|
2246
|
-
try {
|
|
2247
|
-
yield fn();
|
|
2248
|
-
endTimer({ effectName, status: 1 });
|
|
2249
|
-
}
|
|
2250
|
-
catch (error) {
|
|
2251
|
-
endTimer({ effectName, status: 0 });
|
|
2252
|
-
throw error;
|
|
2253
|
-
}
|
|
2254
|
-
});
|
|
2255
|
-
}
|
|
2256
|
-
trackJob(jobName, handler) {
|
|
2257
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
2258
|
-
const endTimer = this.jobHistogram.startTimer();
|
|
2259
|
-
try {
|
|
2260
|
-
yield handler();
|
|
2261
|
-
endTimer({ jobName, status: 1 });
|
|
2262
|
-
}
|
|
2263
|
-
catch (error) {
|
|
2264
|
-
endTimer({ jobName, status: 0 });
|
|
2265
|
-
throw error;
|
|
2266
|
-
}
|
|
2267
|
-
});
|
|
2268
|
-
}
|
|
2269
|
-
trackEventEmitted(eventType) {
|
|
2270
|
-
this.eventCounter.inc({ eventType });
|
|
2271
|
-
}
|
|
2272
|
-
trackCustomPeriodExpression(customPeriod) {
|
|
2273
|
-
this.customPeriodCounter.inc({ customPeriod });
|
|
2274
|
-
}
|
|
2275
|
-
trackUpdatePlayerJobSource(source) {
|
|
2276
|
-
this.updatePlayerJobSourceCounter.inc({ source });
|
|
2277
|
-
}
|
|
2278
|
-
updateQueueMetrics(queueName, counts) {
|
|
2279
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
2280
|
-
for (const [state, count] of Object.entries(counts)) {
|
|
2281
|
-
this.jobQueueGauge.set({ queueName, state }, count);
|
|
2282
|
-
}
|
|
2283
|
-
});
|
|
2284
|
-
}
|
|
2285
|
-
}
|
|
2286
|
-
var prometheusService = new PrometheusService();
|
|
2287
|
-
|
|
2288
2062
|
const CUSTOM_PERIOD_REGEX = /(\d+y)?(\d+m)?(\d+w)?(\d+d)?(\d+h)?/;
|
|
2289
2063
|
const PeriodProps = {
|
|
2290
2064
|
[Period.FIVE_MIN]: { name: '5 Min', milliseconds: 300000 },
|
|
@@ -2312,7 +2086,6 @@ function parsePeriodExpression(periodExpression) {
|
|
|
2312
2086
|
durationMs: PeriodProps[fixed].milliseconds
|
|
2313
2087
|
};
|
|
2314
2088
|
}
|
|
2315
|
-
prometheusService.trackCustomPeriodExpression(fixed);
|
|
2316
2089
|
const result = fixed.match(CUSTOM_PERIOD_REGEX);
|
|
2317
2090
|
if (!result || result.length === 0 || result[0] !== fixed)
|
|
2318
2091
|
return null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wise-old-man/utils",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.13",
|
|
4
4
|
"description": "A JavaScript/TypeScript client that interfaces and consumes the Wise Old Man API, an API that tracks and measures players' progress in Old School Runescape.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"wiseoldman",
|