1- import json from "json-stable-stringify" ;
21import { EventEmitter } from "events" ;
3- import type { JSONValue } from "@cocalc/util/types " ;
4- import { ConatError } from "@cocalc/conat/core/client" ;
2+ import json from "json-stable-stringify " ;
3+
54import { getLogger } from "@cocalc/conat/client" ;
5+ import { ConatError } from "@cocalc/conat/core/client" ;
6+ import type { JSONValue } from "@cocalc/util/types" ;
7+ import { Metrics } from "../types" ;
68
79const logger = getLogger ( "monitor:usage" ) ;
810
@@ -17,6 +19,9 @@ export class UsageMonitor extends EventEmitter {
1719 private options : Options ;
1820 private total = 0 ;
1921 private perUser : { [ user : string ] : number } = { } ;
22+ // metrics will be picked up periodically and exposed via e.g. prometheus
23+ private countDeny = 0 ;
24+ private metrics : Metrics = { } ;
2025
2126 constructor ( options : Options ) {
2227 super ( ) ;
@@ -38,27 +43,53 @@ export class UsageMonitor extends EventEmitter {
3843
3944 private initLogging = ( ) => {
4045 const { log } = this . options ;
41- if ( log == null ) {
42- return ;
43- }
46+
47+ // Record metrics for all events (even if logging is disabled)
4448 this . on ( "total" , ( total , limit ) => {
45- log ( "usage" , this . options . resource , { total, limit } ) ;
49+ this . metrics [ "total:count" ] = total ;
50+ this . metrics [ "total:limit" ] = limit ;
51+ if ( log ) {
52+ log ( "usage" , this . options . resource , { total, limit } ) ;
53+ }
4654 } ) ;
4755 this . on ( "add" , ( user , count , limit ) => {
48- log ( "usage" , this . options . resource , "add" , { user, count, limit } ) ;
56+ // this.metrics["add:count"] = count;
57+ // this.metrics["add:limit"] = limit;
58+ if ( log ) {
59+ log ( "usage" , this . options . resource , "add" , { user, count, limit } ) ;
60+ }
4961 } ) ;
5062 this . on ( "delete" , ( user , count , limit ) => {
51- log ( "usage" , this . options . resource , "delete" , { user, count, limit } ) ;
63+ // this.metrics["delete:count"] = count;
64+ // this.metrics["delete:limit"] = limit;
65+ if ( log ) {
66+ log ( "usage" , this . options . resource , "delete" , { user, count, limit } ) ;
67+ }
5268 } ) ;
5369 this . on ( "deny" , ( user , limit , type ) => {
54- log ( "usage" , this . options . resource , "not allowed due to hitting limit" , {
55- type,
56- user,
57- limit,
58- } ) ;
70+ this . countDeny += 1 ;
71+ this . metrics [ "deny:count" ] = this . countDeny ;
72+ this . metrics [ "deny:limit" ] = limit ;
73+ if ( log ) {
74+ log (
75+ "usage" ,
76+ this . options . resource ,
77+ "not allowed due to hitting limit" ,
78+ {
79+ type,
80+ user,
81+ limit,
82+ } ,
83+ ) ;
84+ }
5985 } ) ;
6086 } ;
6187
88+ // we return a copy
89+ getMetrics = ( ) => {
90+ return { ...this . metrics } ;
91+ } ;
92+
6293 add = ( user : JSONValue ) => {
6394 const u = this . toJson ( user ) ;
6495 let count = this . perUser [ u ] ?? 0 ;
0 commit comments