Skip to content

Commit 7865e35

Browse files
authored
Merge pull request #2430 from bcgov/develop
Deployment PR - 1645
2 parents a2fa00b + 3578c44 commit 7865e35

File tree

4 files changed

+99
-62
lines changed

4 files changed

+99
-62
lines changed

services/apps/alcs/src/main.ts

Lines changed: 19 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,14 @@ import {
1010
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
1111
import * as config from 'config';
1212
import { ClsMiddleware } from 'nestjs-cls';
13-
import { S3StreamLogger, S3StreamLoggerOptions } from 's3-streamlogger';
1413
import { install } from 'source-map-support';
1514
import { SPLAT } from 'triple-beam';
1615
import * as winston from 'winston';
1716
import { createLogger } from 'winston';
1817
import { generateModuleGraph } from './commands/graph';
1918
import { MainModule } from './main.module';
20-
import { S3ClientConfig } from '@aws-sdk/client-s3';
21-
22-
// S3StreamLogger passes its config to S3Client, but doesn't accept all the
23-
// properties of S3ClientConfig. This allows those properties.
24-
interface SafeS3StreamLoggerOptions extends S3StreamLoggerOptions {
25-
config: S3StreamLoggerOptions['config'] & {
26-
forcePathStyle: boolean;
27-
endpoint: string;
28-
};
29-
}
19+
import { S3Client } from '@aws-sdk/client-s3';
20+
import { RotatingS3Writable } from './s3-logger/s3-logger';
3021

3122
const registerSwagger = (app: NestFastifyApplication) => {
3223
const documentBuilderConfig = new DocumentBuilder()
@@ -106,23 +97,22 @@ const registerMultiPart = async (app: NestFastifyApplication) => {
10697
};
10798

10899
function setupLogger() {
109-
const s3StreamOptions: SafeS3StreamLoggerOptions = {
110-
rotate_every: 1000 * 60 * 60 * 24, //1 Day
111-
folder: 'logs',
112-
bucket: config.get<string>('STORAGE.BUCKET'),
113-
name_format: '%Y-%b-%d-console.log', //https://www.npmjs.com/package/strftime
114-
config: {
115-
region: 'us-east-1',
116-
credentials: {
117-
accessKeyId: config.get('STORAGE.ACCESS_KEY'),
118-
secretAccessKey: config.get('STORAGE.SECRET_KEY'),
119-
},
120-
forcePathStyle: true,
121-
endpoint: config.get('STORAGE.URL'),
100+
const s3Client = new S3Client({
101+
region: 'us-east-1',
102+
credentials: {
103+
accessKeyId: config.get('STORAGE.ACCESS_KEY'),
104+
secretAccessKey: config.get('STORAGE.SECRET_KEY'),
122105
},
123-
};
106+
forcePathStyle: true,
107+
endpoint: config.get('STORAGE.URL'),
108+
});
124109

125-
const s3Stream = new S3StreamLogger(s3StreamOptions);
110+
const s3Stream = new RotatingS3Writable({
111+
bucket: config.get<string>('STORAGE.BUCKET'),
112+
folder: 'logs',
113+
rotateEvery: 1000 * 60 * 60 * 24, // 1 day
114+
s3Client,
115+
});
126116

127117
const timeStampFormat = winston.format.timestamp({
128118
format: 'YYYY-MMM-DD HH:mm:ss',
@@ -145,20 +135,11 @@ function setupLogger() {
145135
const s3Transport = new winston.transports.Stream({
146136
level: config.get('LOG_LEVEL'),
147137
stream: s3Stream,
148-
format: winston.format.combine(
149-
winston.format.errors({ stack: true }),
150-
timeStampFormat,
151-
messageFormat,
152-
),
138+
format: winston.format.combine(winston.format.errors({ stack: true }), timeStampFormat, messageFormat),
153139
});
154140
const consoleTransport = new winston.transports.Console({
155141
level: config.get('LOG_LEVEL'),
156-
format: winston.format.combine(
157-
winston.format.errors({ stack: true }),
158-
timeStampFormat,
159-
messageFormat,
160-
colorFormat,
161-
),
142+
format: winston.format.combine(winston.format.errors({ stack: true }), timeStampFormat, messageFormat, colorFormat),
162143
});
163144

164145
return createLogger({
@@ -171,10 +152,7 @@ function setupLogger() {
171152
debug: 5,
172153
verbose: 6,
173154
},
174-
transports:
175-
config.get('ENV') === 'production'
176-
? [consoleTransport, s3Transport]
177-
: [consoleTransport],
155+
transports: config.get('ENV') === 'production' ? [consoleTransport, s3Transport] : [consoleTransport],
178156
});
179157
}
180158

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import { Writable } from 'stream';
2+
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
3+
4+
const MESSAGE_SYMBOL = Symbol.for('message');
5+
6+
interface RotatingS3WritableOptions {
7+
bucket: string;
8+
folder?: string;
9+
rotateEvery?: number;
10+
s3Client: S3Client;
11+
}
12+
13+
export class RotatingS3Writable extends Writable {
14+
private buffer: string[] = [];
15+
private lastRotation: number;
16+
private currentKey: string;
17+
18+
constructor(private options: RotatingS3WritableOptions) {
19+
super({ objectMode: true });
20+
21+
this.lastRotation = Date.now();
22+
this.currentKey = this.generateKey(this.lastRotation);
23+
}
24+
25+
_write(chunk: any, _encoding: BufferEncoding, callback: (error?: Error | null) => void) {
26+
const message = chunk?.[MESSAGE_SYMBOL] ?? chunk?.message ?? '';
27+
28+
if (message) {
29+
this.buffer.push(message);
30+
}
31+
32+
const now = Date.now();
33+
34+
if (this.options.rotateEvery && now - this.lastRotation >= this.options.rotateEvery) {
35+
this.flush()
36+
.then(() => {
37+
this.lastRotation = now;
38+
this.currentKey = this.generateKey(now);
39+
callback();
40+
})
41+
.catch(callback);
42+
} else {
43+
callback();
44+
}
45+
}
46+
47+
private generateKey(dateMs: number): string {
48+
const date = new Date(dateMs);
49+
const year = date.getUTCFullYear();
50+
const month = date.toLocaleString('en-US', { month: 'short', timeZone: 'UTC' });
51+
const day = String(date.getUTCDate()).padStart(2, '0');
52+
53+
const filename = `${year}-${month}-${day}-console.log`;
54+
const prefix = this.options.folder ? `${this.options.folder}/` : '';
55+
56+
return `${prefix}${filename}`;
57+
}
58+
59+
async flush(): Promise<void> {
60+
if (this.buffer.length === 0) return;
61+
62+
const body = this.buffer.join('\n') + '\n';
63+
this.buffer = [];
64+
65+
await this.options.s3Client.send(
66+
new PutObjectCommand({
67+
Bucket: this.options.bucket,
68+
Key: this.currentKey,
69+
Body: body,
70+
ContentType: 'text/plain',
71+
}),
72+
);
73+
}
74+
75+
_final(callback: (error?: Error | null) => void) {
76+
this.flush()
77+
.then(() => callback())
78+
.catch(callback);
79+
}
80+
}

services/package-lock.json

Lines changed: 0 additions & 20 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

services/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@
7070
"reflect-metadata": "^0.1.14",
7171
"rimraf": "^5.0.5",
7272
"rxjs": "^7.8.2",
73-
"s3-streamlogger": "^1.11.1",
7473
"source-map-support": "^0.5.21",
7574
"ts-proto": "^1.171.0",
7675
"ts-protoc-gen": "^0.15.0",

0 commit comments

Comments
 (0)