adonisjs-pulse 0.0.1
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/LICENSE.md +9 -0
- package/README.md +119 -0
- package/build/configure.d.ts +2 -0
- package/build/configure.js +47 -0
- package/build/index.d.ts +5 -0
- package/build/index.js +5 -0
- package/build/providers/pulse_provider.d.ts +16 -0
- package/build/providers/pulse_provider.js +64 -0
- package/build/resources/views/components/card-header.edge +30 -0
- package/build/resources/views/components/card.edge +8 -0
- package/build/resources/views/components/no-results.edge +3 -0
- package/build/resources/views/components/pulse.edge +79 -0
- package/build/resources/views/components/scroll.edge +3 -0
- package/build/resources/views/components/table.edge +3 -0
- package/build/resources/views/components/td.edge +4 -0
- package/build/resources/views/components/th.edge +4 -0
- package/build/resources/views/components/thead.edge +3 -0
- package/build/resources/views/components/theme-switcher.edge +48 -0
- package/build/resources/views/dashboard.edge +7 -0
- package/build/resources/views/livewire/cache.edge +111 -0
- package/build/resources/views/livewire/exceptions.edge +48 -0
- package/build/resources/views/livewire/period-selector.edge +11 -0
- package/build/resources/views/livewire/servers.edge +86 -0
- package/build/resources/views/livewire/slow-queries.edge +50 -0
- package/build/resources/views/livewire/slow-requests.edge +62 -0
- package/build/resources/views/livewire/usage.edge +63 -0
- package/build/services/pulse.d.ts +3 -0
- package/build/services/pulse.js +6 -0
- package/build/src/entry.d.ts +24 -0
- package/build/src/entry.js +67 -0
- package/build/src/livewire/cache.d.ts +4 -0
- package/build/src/livewire/cache.js +33 -0
- package/build/src/livewire/card.d.ts +22 -0
- package/build/src/livewire/card.js +96 -0
- package/build/src/livewire/exceptions.d.ts +4 -0
- package/build/src/livewire/exceptions.js +29 -0
- package/build/src/livewire/period_selector.d.ts +5 -0
- package/build/src/livewire/period_selector.js +16 -0
- package/build/src/livewire/servers.d.ts +4 -0
- package/build/src/livewire/servers.js +36 -0
- package/build/src/livewire/slow_queries.d.ts +5 -0
- package/build/src/livewire/slow_queries.js +37 -0
- package/build/src/livewire/slow_requests.d.ts +5 -0
- package/build/src/livewire/slow_requests.js +37 -0
- package/build/src/pulse.d.ts +44 -0
- package/build/src/pulse.js +224 -0
- package/build/src/recorders/cache_interactions.d.ts +34 -0
- package/build/src/recorders/cache_interactions.js +80 -0
- package/build/src/recorders/exceptions.d.ts +8 -0
- package/build/src/recorders/exceptions.js +81 -0
- package/build/src/recorders/index.d.ts +7 -0
- package/build/src/recorders/index.js +6 -0
- package/build/src/recorders/recorder.d.ts +24 -0
- package/build/src/recorders/recorder.js +45 -0
- package/build/src/recorders/servers.d.ts +24 -0
- package/build/src/recorders/servers.js +133 -0
- package/build/src/recorders/slow_queries.d.ts +8 -0
- package/build/src/recorders/slow_queries.js +27 -0
- package/build/src/recorders/slow_requests.d.ts +11 -0
- package/build/src/recorders/slow_requests.js +80 -0
- package/build/src/storage/database_storage.d.ts +20 -0
- package/build/src/storage/database_storage.js +357 -0
- package/build/src/types.d.ts +91 -0
- package/build/src/types.js +3 -0
- package/build/src/value.d.ts +9 -0
- package/build/src/value.js +20 -0
- package/build/stubs/config.stub +58 -0
- package/build/stubs/main.d.ts +5 -0
- package/build/stubs/main.js +7 -0
- package/build/stubs/migration.stub +58 -0
- package/package.json +100 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { Entry } from './entry.js';
|
|
2
|
+
import type { Value } from './value.js';
|
|
3
|
+
import type { Recorder, RecorderOptions } from './recorders/recorder.js';
|
|
4
|
+
export type AggregationType = 'count' | 'min' | 'max' | 'sum' | 'avg';
|
|
5
|
+
export interface EntryAttributes {
|
|
6
|
+
timestamp: number;
|
|
7
|
+
type: string;
|
|
8
|
+
key: string;
|
|
9
|
+
value: number | null;
|
|
10
|
+
}
|
|
11
|
+
export interface ValueAttributes {
|
|
12
|
+
timestamp: number;
|
|
13
|
+
type: string;
|
|
14
|
+
key: string;
|
|
15
|
+
value: string;
|
|
16
|
+
}
|
|
17
|
+
export interface StoredEntry extends EntryAttributes {
|
|
18
|
+
id: number;
|
|
19
|
+
key_hash: string;
|
|
20
|
+
}
|
|
21
|
+
export interface StoredValue extends ValueAttributes {
|
|
22
|
+
id: number;
|
|
23
|
+
key_hash: string;
|
|
24
|
+
}
|
|
25
|
+
export interface StoredAggregate {
|
|
26
|
+
id: number;
|
|
27
|
+
bucket: number;
|
|
28
|
+
period: number;
|
|
29
|
+
type: string;
|
|
30
|
+
key: string;
|
|
31
|
+
key_hash: string;
|
|
32
|
+
aggregate: AggregationType;
|
|
33
|
+
value: number;
|
|
34
|
+
count: number | null;
|
|
35
|
+
}
|
|
36
|
+
export interface AggregateResult {
|
|
37
|
+
key: string;
|
|
38
|
+
count?: number;
|
|
39
|
+
min?: number;
|
|
40
|
+
max?: number;
|
|
41
|
+
sum?: number;
|
|
42
|
+
avg?: number;
|
|
43
|
+
}
|
|
44
|
+
export interface AggregateTypesResult {
|
|
45
|
+
key: string;
|
|
46
|
+
[type: string]: string | number | undefined;
|
|
47
|
+
}
|
|
48
|
+
export type LazyRecorder = () => Promise<{
|
|
49
|
+
default: new (options?: RecorderOptions) => Recorder;
|
|
50
|
+
}>;
|
|
51
|
+
export interface RecorderEntry extends RecorderOptions {
|
|
52
|
+
recorder: LazyRecorder;
|
|
53
|
+
}
|
|
54
|
+
export interface PulseConfig {
|
|
55
|
+
enabled: boolean;
|
|
56
|
+
storage: {
|
|
57
|
+
connection?: string;
|
|
58
|
+
};
|
|
59
|
+
ingest: {
|
|
60
|
+
interval: number;
|
|
61
|
+
lottery: {
|
|
62
|
+
chance: number;
|
|
63
|
+
outOf: number;
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
recorders: RecorderEntry[];
|
|
67
|
+
}
|
|
68
|
+
export interface ResolvedPulseConfig {
|
|
69
|
+
enabled: boolean;
|
|
70
|
+
ingestInterval: number;
|
|
71
|
+
trimLotteryChance: [number, number];
|
|
72
|
+
connection?: string;
|
|
73
|
+
retain: {
|
|
74
|
+
entries: number;
|
|
75
|
+
values: number;
|
|
76
|
+
aggregates: number;
|
|
77
|
+
};
|
|
78
|
+
recorders: RecorderEntry[];
|
|
79
|
+
}
|
|
80
|
+
export interface PulseStorage {
|
|
81
|
+
store(entries: Entry[], values: Value[]): Promise<void>;
|
|
82
|
+
trim(): Promise<void>;
|
|
83
|
+
purge(types?: string[]): Promise<void>;
|
|
84
|
+
values(type: string, keys?: string[]): Promise<StoredValue[]>;
|
|
85
|
+
aggregate(type: string, aggregates: AggregationType[], interval: number, orderBy?: AggregationType, direction?: 'asc' | 'desc', limit?: number): Promise<Map<string, AggregateResult>>;
|
|
86
|
+
aggregateTypes(types: string[], aggregate: AggregationType, interval: number, orderBy?: string, direction?: 'asc' | 'desc', limit?: number): Promise<AggregateTypesResult[]>;
|
|
87
|
+
aggregateTotal(types: string[], aggregate: AggregationType, interval: number): Promise<Record<string, number>>;
|
|
88
|
+
graph(types: string[], aggregate: AggregationType, interval: number): Promise<Map<number, Map<string, number>>>;
|
|
89
|
+
}
|
|
90
|
+
export type RecordCallback = () => Entry | Value | Entry[] | Value[] | null | Promise<Entry | Value | Entry[] | Value[] | null>;
|
|
91
|
+
export declare function defineConfig(config: PulseConfig): PulseConfig;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export class Value {
|
|
2
|
+
timestamp;
|
|
3
|
+
type;
|
|
4
|
+
key;
|
|
5
|
+
value;
|
|
6
|
+
constructor(timestamp, type, key, value) {
|
|
7
|
+
this.timestamp = timestamp;
|
|
8
|
+
this.type = type;
|
|
9
|
+
this.key = key;
|
|
10
|
+
this.value = value;
|
|
11
|
+
}
|
|
12
|
+
attributes() {
|
|
13
|
+
return {
|
|
14
|
+
timestamp: this.timestamp,
|
|
15
|
+
type: this.type,
|
|
16
|
+
key: this.key,
|
|
17
|
+
value: this.value,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{{{
|
|
2
|
+
exports({ to: app.configPath('pulse.ts') })
|
|
3
|
+
}}}
|
|
4
|
+
import env from '#start/env'
|
|
5
|
+
import { defineConfig } from 'adonisjs-pulse'
|
|
6
|
+
|
|
7
|
+
export default defineConfig({
|
|
8
|
+
enabled: env.get('PULSE_ENABLED', true),
|
|
9
|
+
|
|
10
|
+
storage: {
|
|
11
|
+
connection: env.get('PULSE_DB_CONNECTION'),
|
|
12
|
+
},
|
|
13
|
+
|
|
14
|
+
ingest: {
|
|
15
|
+
interval: 5000,
|
|
16
|
+
lottery: {
|
|
17
|
+
chance: 1,
|
|
18
|
+
outOf: 1000,
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
recorders: [
|
|
23
|
+
{
|
|
24
|
+
recorder: () => import('adonisjs-pulse/recorders/slow_requests'),
|
|
25
|
+
enabled: env.get('PULSE_SLOW_REQUESTS_ENABLED', true),
|
|
26
|
+
sampleRate: env.get('PULSE_SLOW_REQUESTS_SAMPLE_RATE', 1),
|
|
27
|
+
threshold: env.get('PULSE_SLOW_REQUESTS_THRESHOLD', 1000),
|
|
28
|
+
ignore: ['/pulse'],
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
recorder: () => import('adonisjs-pulse/recorders/slow_queries'),
|
|
32
|
+
enabled: env.get('PULSE_SLOW_QUERIES_ENABLED', true),
|
|
33
|
+
sampleRate: env.get('PULSE_SLOW_QUERIES_SAMPLE_RATE', 1),
|
|
34
|
+
threshold: env.get('PULSE_SLOW_QUERIES_THRESHOLD', 1000),
|
|
35
|
+
ignore: ['/pulse_/'],
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
recorder: () => import('adonisjs-pulse/recorders/exceptions'),
|
|
39
|
+
enabled: env.get('PULSE_EXCEPTIONS_ENABLED', true),
|
|
40
|
+
sampleRate: env.get('PULSE_EXCEPTIONS_SAMPLE_RATE', 1),
|
|
41
|
+
ignore: [],
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
recorder: () => import('adonisjs-pulse/recorders/servers'),
|
|
45
|
+
enabled: env.get('PULSE_SERVERS_ENABLED', true),
|
|
46
|
+
directories: ['/'],
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
recorder: () => import('adonisjs-pulse/recorders/cache_interactions'),
|
|
50
|
+
enabled: env.get('PULSE_CACHE_INTERACTIONS_ENABLED', true),
|
|
51
|
+
sampleRate: env.get('PULSE_CACHE_INTERACTIONS_SAMPLE_RATE', 1),
|
|
52
|
+
ignore: [],
|
|
53
|
+
groups: {
|
|
54
|
+
'/^job-exceptions:.*/': 'job-exceptions:*',
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
})
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { dirname } from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
/**
|
|
4
|
+
* Path to the root directory where the stubs are stored. We use
|
|
5
|
+
* this path within commands and the configure hook
|
|
6
|
+
*/
|
|
7
|
+
export const stubsRoot = dirname(fileURLToPath(import.meta.url));
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{{{
|
|
2
|
+
exports({ to: app.migrationsPath(time + '_create_pulse_tables.ts') })
|
|
3
|
+
}}}
|
|
4
|
+
import { BaseSchema } from '@adonisjs/lucid/schema'
|
|
5
|
+
|
|
6
|
+
export default class extends BaseSchema {
|
|
7
|
+
async up() {
|
|
8
|
+
this.schema.createTable('pulse_values', (table) => {
|
|
9
|
+
table.increments('id')
|
|
10
|
+
table.integer('timestamp').unsigned()
|
|
11
|
+
table.string('type')
|
|
12
|
+
table.text('key', 'medium')
|
|
13
|
+
table.string('key_hash')
|
|
14
|
+
table.text('value', 'medium')
|
|
15
|
+
|
|
16
|
+
table.index('timestamp') // For trimming...
|
|
17
|
+
table.index('type') // For fast lookups and purging...
|
|
18
|
+
table.unique(['type', 'key_hash']) // For data integrity and upserts...
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
this.schema.createTable('pulse_entries', (table) => {
|
|
22
|
+
table.increments('id')
|
|
23
|
+
table.integer('timestamp').unsigned()
|
|
24
|
+
table.string('type')
|
|
25
|
+
table.text('key', 'medium')
|
|
26
|
+
table.string('key_hash')
|
|
27
|
+
table.bigInteger('value').nullable()
|
|
28
|
+
|
|
29
|
+
table.index('timestamp') // For trimming...
|
|
30
|
+
table.index('type') // For purging...
|
|
31
|
+
table.index('key_hash') // For mapping...
|
|
32
|
+
table.index(['timestamp', 'type', 'key_hash', 'value']) // For aggregate queries...
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
this.schema.createTable('pulse_aggregates', (table) => {
|
|
36
|
+
table.increments('id')
|
|
37
|
+
table.integer('bucket').unsigned()
|
|
38
|
+
table.mediumint('period').unsigned()
|
|
39
|
+
table.string('type')
|
|
40
|
+
table.text('key', 'medium')
|
|
41
|
+
table.string('key_hash')
|
|
42
|
+
table.string('aggregate')
|
|
43
|
+
table.decimal('value', 20, 2)
|
|
44
|
+
table.integer('count').nullable()
|
|
45
|
+
|
|
46
|
+
table.unique(['bucket', 'period', 'type', 'aggregate', 'key_hash']) // Force "on duplicate update"...
|
|
47
|
+
table.index(['period', 'bucket']) // For trimming...
|
|
48
|
+
table.index('type') // For purging...
|
|
49
|
+
table.index(['period', 'type', 'aggregate', 'bucket']) // For aggregate queries...
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async down() {
|
|
54
|
+
this.schema.dropTable('pulse_values')
|
|
55
|
+
this.schema.dropTable('pulse_entries')
|
|
56
|
+
this.schema.dropTable('pulse_aggregates')
|
|
57
|
+
}
|
|
58
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "adonisjs-pulse",
|
|
3
|
+
"description": "",
|
|
4
|
+
"version": "0.0.1",
|
|
5
|
+
"engines": {
|
|
6
|
+
"node": ">=20.6.0"
|
|
7
|
+
},
|
|
8
|
+
"type": "module",
|
|
9
|
+
"files": [
|
|
10
|
+
"build/src",
|
|
11
|
+
"build/providers",
|
|
12
|
+
"build/services",
|
|
13
|
+
"build/stubs",
|
|
14
|
+
"build/resources",
|
|
15
|
+
"build/index.d.ts",
|
|
16
|
+
"build/index.js",
|
|
17
|
+
"build/configure.d.ts",
|
|
18
|
+
"build/configure.js"
|
|
19
|
+
],
|
|
20
|
+
"exports": {
|
|
21
|
+
".": "./build/index.js",
|
|
22
|
+
"./types": "./build/src/types.js",
|
|
23
|
+
"./pulse_provider": "./build/providers/pulse_provider.js",
|
|
24
|
+
"./services/pulse": "./build/services/pulse.js",
|
|
25
|
+
"./recorders/slow_requests": "./build/src/recorders/slow_requests.js",
|
|
26
|
+
"./recorders/slow_queries": "./build/src/recorders/slow_queries.js",
|
|
27
|
+
"./recorders/exceptions": "./build/src/recorders/exceptions.js",
|
|
28
|
+
"./recorders/servers": "./build/src/recorders/servers.js",
|
|
29
|
+
"./recorders/cache_interactions": "./build/src/recorders/cache_interactions.js"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [],
|
|
32
|
+
"author": "",
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@adonisjs/assembler": "^7.8.2",
|
|
36
|
+
"@adonisjs/core": "^6.12.0",
|
|
37
|
+
"@adonisjs/eslint-config": "2.0.0-beta.7",
|
|
38
|
+
"@adonisjs/lucid": "^21.8.2",
|
|
39
|
+
"@adonisjs/prettier-config": "^1.4.0",
|
|
40
|
+
"@adonisjs/tsconfig": "^1.3.0",
|
|
41
|
+
"@japa/assert": "^3.0.0",
|
|
42
|
+
"@japa/runner": "^3.1.4",
|
|
43
|
+
"@swc/core": "^1.6.3",
|
|
44
|
+
"@types/node": "^20.14.5",
|
|
45
|
+
"adonisjs-livewire": "^0.15.1",
|
|
46
|
+
"c8": "^10.1.2",
|
|
47
|
+
"copyfiles": "^2.4.1",
|
|
48
|
+
"del-cli": "^5.1.0",
|
|
49
|
+
"edge.js": "^6.4.0",
|
|
50
|
+
"eslint": "^9.15.0",
|
|
51
|
+
"np": "^10.0.6",
|
|
52
|
+
"prettier": "^3.3.2",
|
|
53
|
+
"ts-node-maintained": "^10.9.4",
|
|
54
|
+
"typescript": "^5.4.5"
|
|
55
|
+
},
|
|
56
|
+
"peerDependencies": {
|
|
57
|
+
"@adonisjs/core": "^6.2.0",
|
|
58
|
+
"@adonisjs/lucid": "^21.8.2",
|
|
59
|
+
"adonisjs-livewire": "^0.15.1",
|
|
60
|
+
"edge.js": "^6.4.0"
|
|
61
|
+
},
|
|
62
|
+
"publishConfig": {
|
|
63
|
+
"access": "public",
|
|
64
|
+
"tag": "latest"
|
|
65
|
+
},
|
|
66
|
+
"np": {
|
|
67
|
+
"message": "chore(release): %s",
|
|
68
|
+
"tag": "latest",
|
|
69
|
+
"branch": "main",
|
|
70
|
+
"anyBranch": false
|
|
71
|
+
},
|
|
72
|
+
"c8": {
|
|
73
|
+
"reporter": [
|
|
74
|
+
"text",
|
|
75
|
+
"html"
|
|
76
|
+
],
|
|
77
|
+
"exclude": [
|
|
78
|
+
"tests/**"
|
|
79
|
+
]
|
|
80
|
+
},
|
|
81
|
+
"prettier": "@adonisjs/prettier-config",
|
|
82
|
+
"dependencies": {
|
|
83
|
+
"unreflect": "^0.0.7"
|
|
84
|
+
},
|
|
85
|
+
"scripts": {
|
|
86
|
+
"clean": "del-cli build",
|
|
87
|
+
"copy:templates": "copyfiles \"stubs/**/*.stub\" \"resources/**/*\" build",
|
|
88
|
+
"typecheck": "tsc --noEmit",
|
|
89
|
+
"lint": "eslint .",
|
|
90
|
+
"format": "prettier --write .",
|
|
91
|
+
"quick:test": "node --import=./tsnode.esm.js --enable-source-maps bin/test.ts",
|
|
92
|
+
"pretest": "npm run lint",
|
|
93
|
+
"test": "c8 npm run quick:test",
|
|
94
|
+
"prebuild": "npm run lint && npm run clean",
|
|
95
|
+
"build": "tsc",
|
|
96
|
+
"postbuild": "npm run copy:templates",
|
|
97
|
+
"release": "np",
|
|
98
|
+
"version": "npm run build"
|
|
99
|
+
}
|
|
100
|
+
}
|