@payfit/audit-log 3.11.0 → 3.13.0
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/compression.d.ts +2 -0
- package/dist/compression.test.d.ts +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.mjs +81 -57
- package/dist/metrics.d.ts +2 -1
- package/dist/transport/implementation.d.ts +6 -3
- package/dist/transport/interface.d.ts +4 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export type AuditTargets = 'reporting' | 'employee' | 'employee.settings' | 'emp
|
|
|
12
12
|
/**
|
|
13
13
|
* The allowed Events for the AuditLog
|
|
14
14
|
*/
|
|
15
|
-
export type AuditEvents = 'create' | 'update' | 'share' | 'delete' | 'view' | 'sign' | 'signin' | 'signinFail' | 'signinAs' | 'logout' | 'updateCurrentAccount' | 'merge' | 'disable' | 'sendResetPasswordLink' | 'enable' | 'verify' | 'read' | 'write' | 'subscribe' | 'consume' | 'setup' | 'deleteAllAdmins' | 'import';
|
|
15
|
+
export type AuditEvents = 'create' | 'update' | 'share' | 'delete' | 'view' | 'sign' | 'signin' | 'signinFail' | 'signinAs' | 'logout' | 'updateCurrentAccount' | 'merge' | 'disable' | 'sendResetPasswordLink' | 'enable' | 'verify' | 'read' | 'write' | 'subscribe' | 'consume' | 'setup' | 'deleteAllAdmins' | 'import' | 'useAccount';
|
|
16
16
|
/**
|
|
17
17
|
* Data to audit log.
|
|
18
18
|
*/
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var f=Object.defineProperty;var w=(s,e,t)=>e in s?f(s,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):s[e]=t;var n=(s,e,t)=>(w(s,typeof e!="symbol"?e+"":e,t),t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const S=require("uuid"),a=require("winston"),v=require("hot-shots"),h=require("@aws-sdk/client-sqs"),E=require("zlib"),y="audit-logs",_="@payfit/audit-log",q=()=>{const s=process.env.LOG_LEVEL;return s&&s.trim()!==""?s.trim():"info"},L=(s,e)=>a.createLogger({level:q(),silent:process.env.NODE_ENV==="test",exitOnError:!1,defaultMeta:{namespace:y,sdk:_,service:s,environment:e},format:a.format.combine(a.format.timestamp(),a.format.errors({stack:!0}),a.format.json()),transports:[new a.transports.Console]}),M="payfit.audit_logs.",p=s=>Object.entries(s).filter(([,e])=>e!==void 0&&e!=="").map(([e,t])=>`${e}:${String(t)}`);class A{constructor(){n(this,"client");this.client=new v.StatsD({prefix:M,errorHandler:()=>{},cacheDns:!0})}increment(e,t){this.client.increment(e,1,p(t))}histogram(e,t,i){this.client.histogram(e,t,p(i))}async close(){await new Promise(e=>{this.client.close(()=>e())})}}const b=()=>new A;function C(s){return E.brotliCompressSync(Buffer.from(s,"utf8")).toString("base64")}function U(s){return s instanceof Error&&s.message.includes("Message must be shorter than")}const O="eu-west-3",z={dev:"https://sqs.eu-west-3.amazonaws.com/533547282673/audit-logs-ingest",staging:"https://sqs.eu-west-3.amazonaws.com/589883667243/audit-logs-ingest",prod:"https://sqs.eu-west-3.amazonaws.com/614948436281/audit-logs-ingest"},D={working:"staging",production:"prod"};class N{constructor(e,t){n(this,"environment");n(this,"logger");n(this,"client");n(this,"queueUrl");this.environment=e,this.logger=t;const i=D[e]??e,o=z[i];if(!o)throw new Error(`audit-logs SDK: no SQS queue URL configured for environment "${e}"`);this.queueUrl=o,this.client=new h.SQSClient({region:O})}async create(e){var i;const t=JSON.stringify(e);try{return await this.send(t),{compressed:!1}}catch(o){if(!U(o))throw o;return(i=this.logger)==null||i.info("audit-log payload exceeds the SQS size limit, retrying with Brotli compression",{id:e.id,namespace:e.namespace}),await this.send(C(t)),{compressed:!0}}}async send(e){await this.client.send(new h.SendMessageCommand({QueueUrl:this.queueUrl,MessageBody:e}))}}class Q{constructor(e,t={}){n(this,"params");n(this,"transport");n(this,"logger");n(this,"metrics");this.params=e,this.logger=t.logger??L(e.service,e.environment),this.transport=t.transport??new N(e.environment,this.logger),this.metrics=t.metrics??b()}async log({scope:e,account:t,...i}){const o=S.v4(),{environment:l,service:m}=this.params,r={...i,...t,service:m,id:o,environment:l,...e&&{scope:e}},c={service:m,environment:l,namespace:r.namespace,event:r.event,target:r.target},u=Date.now();try{const{compressed:g}=await this.transport.create(r);this.metrics.increment("sent",{...c,compressed:String(g)}),this.metrics.histogram("send_duration_ms",Date.now()-u,c),this.logger.debug("audit-log sent",{id:r.id,event:r.event,target:r.target})}catch(g){this.metrics.increment("send_failed",c),this.metrics.histogram("send_duration_ms",Date.now()-u,c);const d=g.message;try{this.logger.error("audit-log write failed",{audit_log:r,error:d})}catch{this.metrics.increment("serialization_failed",c);try{this.logger.error("audit-log write failed (serialization failed)",{audit_log_meta:{id:r.id,service:r.service,environment:r.environment,namespace:r.namespace,event:r.event,target:r.target},error:d})}catch{}}}}}exports.AuditLogger=Q;
|
package/dist/index.mjs
CHANGED
|
@@ -1,114 +1,138 @@
|
|
|
1
1
|
var p = Object.defineProperty;
|
|
2
|
-
var
|
|
3
|
-
var i = (s,
|
|
4
|
-
import { v4 as
|
|
5
|
-
import { createLogger as
|
|
6
|
-
import { StatsD as
|
|
7
|
-
import { SQSClient as
|
|
8
|
-
|
|
2
|
+
var f = (s, e, t) => e in s ? p(s, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : s[e] = t;
|
|
3
|
+
var i = (s, e, t) => (f(s, typeof e != "symbol" ? e + "" : e, t), t);
|
|
4
|
+
import { v4 as w } from "uuid";
|
|
5
|
+
import { createLogger as v, format as c, transports as S } from "winston";
|
|
6
|
+
import { StatsD as E } from "hot-shots";
|
|
7
|
+
import { SQSClient as _, SendMessageCommand as y } from "@aws-sdk/client-sqs";
|
|
8
|
+
import { brotliCompressSync as L } from "zlib";
|
|
9
|
+
const M = "audit-logs", A = "@payfit/audit-log", C = () => {
|
|
9
10
|
const s = process.env.LOG_LEVEL;
|
|
10
11
|
return s && s.trim() !== "" ? s.trim() : "info";
|
|
11
|
-
},
|
|
12
|
-
level:
|
|
12
|
+
}, U = (s, e) => v({
|
|
13
|
+
level: C(),
|
|
13
14
|
silent: process.env.NODE_ENV === "test",
|
|
14
15
|
exitOnError: !1,
|
|
15
16
|
defaultMeta: {
|
|
16
|
-
namespace:
|
|
17
|
+
namespace: M,
|
|
17
18
|
sdk: A,
|
|
18
19
|
service: s,
|
|
19
|
-
environment:
|
|
20
|
+
environment: e
|
|
20
21
|
},
|
|
21
|
-
format:
|
|
22
|
-
transports: [new
|
|
23
|
-
}),
|
|
24
|
-
class
|
|
22
|
+
format: c.combine(c.timestamp(), c.errors({ stack: !0 }), c.json()),
|
|
23
|
+
transports: [new S.Console()]
|
|
24
|
+
}), q = "payfit.audit_logs.", h = (s) => Object.entries(s).filter(([, e]) => e !== void 0 && e !== "").map(([e, t]) => `${e}:${String(t)}`);
|
|
25
|
+
class b {
|
|
25
26
|
constructor() {
|
|
26
27
|
i(this, "client");
|
|
27
|
-
this.client = new
|
|
28
|
-
prefix:
|
|
28
|
+
this.client = new E({
|
|
29
|
+
prefix: q,
|
|
29
30
|
// Loss of metrics never breaks the caller — DogStatsD UDP is best-effort by design.
|
|
30
31
|
errorHandler: () => {
|
|
31
32
|
},
|
|
32
33
|
cacheDns: !0
|
|
33
34
|
});
|
|
34
35
|
}
|
|
35
|
-
increment(
|
|
36
|
-
this.client.increment(
|
|
36
|
+
increment(e, t) {
|
|
37
|
+
this.client.increment(e, 1, h(t));
|
|
37
38
|
}
|
|
38
|
-
histogram(
|
|
39
|
-
this.client.histogram(
|
|
39
|
+
histogram(e, t, n) {
|
|
40
|
+
this.client.histogram(e, t, h(n));
|
|
40
41
|
}
|
|
41
42
|
async close() {
|
|
42
|
-
await new Promise((
|
|
43
|
-
this.client.close(() =>
|
|
43
|
+
await new Promise((e) => {
|
|
44
|
+
this.client.close(() => e());
|
|
44
45
|
});
|
|
45
46
|
}
|
|
46
47
|
}
|
|
47
|
-
const
|
|
48
|
+
const D = () => new b();
|
|
49
|
+
function N(s) {
|
|
50
|
+
return L(Buffer.from(s, "utf8")).toString("base64");
|
|
51
|
+
}
|
|
52
|
+
function O(s) {
|
|
53
|
+
return s instanceof Error && s.message.includes("Message must be shorter than");
|
|
54
|
+
}
|
|
55
|
+
const z = "eu-west-3", Q = {
|
|
48
56
|
dev: "https://sqs.eu-west-3.amazonaws.com/533547282673/audit-logs-ingest",
|
|
49
57
|
staging: "https://sqs.eu-west-3.amazonaws.com/589883667243/audit-logs-ingest",
|
|
50
58
|
prod: "https://sqs.eu-west-3.amazonaws.com/614948436281/audit-logs-ingest"
|
|
51
|
-
},
|
|
59
|
+
}, R = {
|
|
52
60
|
working: "staging",
|
|
53
61
|
production: "prod"
|
|
54
62
|
};
|
|
55
|
-
class
|
|
56
|
-
constructor(t) {
|
|
63
|
+
class k {
|
|
64
|
+
constructor(e, t) {
|
|
57
65
|
i(this, "environment");
|
|
66
|
+
i(this, "logger");
|
|
58
67
|
i(this, "client");
|
|
59
68
|
i(this, "queueUrl");
|
|
60
|
-
this.environment = t;
|
|
61
|
-
const
|
|
62
|
-
if (!
|
|
63
|
-
throw new Error(`audit-logs SDK: no SQS queue URL configured for environment "${
|
|
64
|
-
this.queueUrl =
|
|
69
|
+
this.environment = e, this.logger = t;
|
|
70
|
+
const n = R[e] ?? e, o = Q[n];
|
|
71
|
+
if (!o)
|
|
72
|
+
throw new Error(`audit-logs SDK: no SQS queue URL configured for environment "${e}"`);
|
|
73
|
+
this.queueUrl = o, this.client = new _({ region: z });
|
|
74
|
+
}
|
|
75
|
+
async create(e) {
|
|
76
|
+
var n;
|
|
77
|
+
const t = JSON.stringify(e);
|
|
78
|
+
try {
|
|
79
|
+
return await this.send(t), { compressed: !1 };
|
|
80
|
+
} catch (o) {
|
|
81
|
+
if (!O(o))
|
|
82
|
+
throw o;
|
|
83
|
+
return (n = this.logger) == null || n.info("audit-log payload exceeds the SQS size limit, retrying with Brotli compression", { id: e.id, namespace: e.namespace }), await this.send(N(t)), { compressed: !0 };
|
|
84
|
+
}
|
|
65
85
|
}
|
|
66
|
-
async
|
|
67
|
-
await this.client.send(new
|
|
86
|
+
async send(e) {
|
|
87
|
+
await this.client.send(new y({
|
|
68
88
|
QueueUrl: this.queueUrl,
|
|
69
|
-
MessageBody:
|
|
89
|
+
MessageBody: e
|
|
70
90
|
}));
|
|
71
91
|
}
|
|
72
92
|
}
|
|
73
|
-
class
|
|
74
|
-
constructor(
|
|
93
|
+
class V {
|
|
94
|
+
constructor(e, t = {}) {
|
|
75
95
|
i(this, "params");
|
|
76
96
|
i(this, "transport");
|
|
77
97
|
i(this, "logger");
|
|
78
98
|
i(this, "metrics");
|
|
79
|
-
this.params =
|
|
99
|
+
this.params = e, this.logger = t.logger ?? U(e.service, e.environment), this.transport = t.transport ?? new k(e.environment, this.logger), this.metrics = t.metrics ?? D();
|
|
80
100
|
}
|
|
81
|
-
async log({ scope:
|
|
82
|
-
const
|
|
101
|
+
async log({ scope: e, account: t, ...n }) {
|
|
102
|
+
const o = w(), { environment: m, service: l } = this.params, r = {
|
|
83
103
|
...n,
|
|
84
|
-
...
|
|
85
|
-
service:
|
|
86
|
-
id:
|
|
87
|
-
environment:
|
|
88
|
-
...
|
|
89
|
-
},
|
|
90
|
-
service:
|
|
91
|
-
environment:
|
|
104
|
+
...t,
|
|
105
|
+
service: l,
|
|
106
|
+
id: o,
|
|
107
|
+
environment: m,
|
|
108
|
+
...e && { scope: e }
|
|
109
|
+
}, a = {
|
|
110
|
+
service: l,
|
|
111
|
+
environment: m,
|
|
92
112
|
namespace: r.namespace,
|
|
93
113
|
event: r.event,
|
|
94
114
|
target: r.target
|
|
95
|
-
},
|
|
115
|
+
}, d = Date.now();
|
|
96
116
|
try {
|
|
97
|
-
|
|
117
|
+
const { compressed: g } = await this.transport.create(r);
|
|
118
|
+
this.metrics.increment("sent", {
|
|
119
|
+
...a,
|
|
120
|
+
compressed: String(g)
|
|
121
|
+
}), this.metrics.histogram("send_duration_ms", Date.now() - d, a), this.logger.debug("audit-log sent", {
|
|
98
122
|
id: r.id,
|
|
99
123
|
event: r.event,
|
|
100
124
|
target: r.target
|
|
101
125
|
});
|
|
102
|
-
} catch (
|
|
103
|
-
this.metrics.increment("send_failed",
|
|
104
|
-
const
|
|
126
|
+
} catch (g) {
|
|
127
|
+
this.metrics.increment("send_failed", a), this.metrics.histogram("send_duration_ms", Date.now() - d, a);
|
|
128
|
+
const u = g.message;
|
|
105
129
|
try {
|
|
106
130
|
this.logger.error("audit-log write failed", {
|
|
107
131
|
audit_log: r,
|
|
108
|
-
error:
|
|
132
|
+
error: u
|
|
109
133
|
});
|
|
110
134
|
} catch {
|
|
111
|
-
this.metrics.increment("serialization_failed",
|
|
135
|
+
this.metrics.increment("serialization_failed", a);
|
|
112
136
|
try {
|
|
113
137
|
this.logger.error("audit-log write failed (serialization failed)", {
|
|
114
138
|
audit_log_meta: {
|
|
@@ -119,7 +143,7 @@ class x {
|
|
|
119
143
|
event: r.event,
|
|
120
144
|
target: r.target
|
|
121
145
|
},
|
|
122
|
-
error:
|
|
146
|
+
error: u
|
|
123
147
|
});
|
|
124
148
|
} catch {
|
|
125
149
|
}
|
|
@@ -128,5 +152,5 @@ class x {
|
|
|
128
152
|
}
|
|
129
153
|
}
|
|
130
154
|
export {
|
|
131
|
-
|
|
155
|
+
V as AuditLogger
|
|
132
156
|
};
|
package/dist/metrics.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const METRIC_PREFIX = "payfit.
|
|
1
|
+
export declare const METRIC_PREFIX = "payfit.audit_logs.";
|
|
2
2
|
export type MetricName = 'sent' | 'send_failed' | 'serialization_failed' | 'send_duration_ms';
|
|
3
3
|
export interface MetricTags {
|
|
4
4
|
service: string;
|
|
@@ -6,6 +6,7 @@ export interface MetricTags {
|
|
|
6
6
|
namespace?: string;
|
|
7
7
|
event?: string;
|
|
8
8
|
target?: string;
|
|
9
|
+
compressed?: string;
|
|
9
10
|
}
|
|
10
11
|
export interface IMetricsClient {
|
|
11
12
|
increment(name: MetricName, tags: MetricTags): void;
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Logger } from 'winston';
|
|
2
|
+
import { IAuditLogCreationData, IAuditLogCreationResult, IAuditLogTransport } from './interface';
|
|
2
3
|
export declare class Transport implements IAuditLogTransport {
|
|
3
4
|
protected environment: string;
|
|
5
|
+
private logger?;
|
|
4
6
|
private client;
|
|
5
7
|
private queueUrl;
|
|
6
|
-
constructor(environment: string);
|
|
7
|
-
create(auditLogData: IAuditLogCreationData): Promise<
|
|
8
|
+
constructor(environment: string, logger?: Logger | undefined);
|
|
9
|
+
create(auditLogData: IAuditLogCreationData): Promise<IAuditLogCreationResult>;
|
|
10
|
+
private send;
|
|
8
11
|
}
|
|
@@ -20,6 +20,9 @@ export interface IAuditLogCreationData {
|
|
|
20
20
|
specialRole?: string;
|
|
21
21
|
email?: string;
|
|
22
22
|
}
|
|
23
|
+
export interface IAuditLogCreationResult {
|
|
24
|
+
compressed: boolean;
|
|
25
|
+
}
|
|
23
26
|
export interface IAuditLogTransport {
|
|
24
|
-
create: (data: IAuditLogCreationData) => Promise<
|
|
27
|
+
create: (data: IAuditLogCreationData) => Promise<IAuditLogCreationResult>;
|
|
25
28
|
}
|