Skip to content

Commit bbf1bb0

Browse files
authored
Merge pull request #534 from sivertschou/add-logging
Add logging with winston and Better Stack Logtail
2 parents e44f981 + 27fde6a commit bbf1bb0

10 files changed

Lines changed: 319 additions & 16 deletions

File tree

.github/actions/deploy/action.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ inputs:
1717
type: string
1818
discord_webhook_url:
1919
type: string
20+
logtail_token:
21+
type: string
2022
mail_host:
2123
required: true
2224
type: string
@@ -88,6 +90,7 @@ runs:
8890
DATABASE_URL=${{ inputs.database_url }} \
8991
DATABASE_PASSWORD=${{ inputs.database_password }} \
9092
DISCORD_WEBHOOK_URL=${{ inputs.discord_webhook_url }} \
93+
LOGTAIL_TOKEN=${{ inputs.logtail_token }} \
9194
REDIS_URL=${{ inputs.redis_url }} \
9295
MAIL_HOST=${{ inputs.mail_host }} \
9396
MAIL_PORT=${{ inputs.mail_port }} \
@@ -140,6 +143,7 @@ runs:
140143
DATABASE_URL=${{ inputs.database_url }} \
141144
DATABASE_PASSWORD=${{ inputs.database_password }} \
142145
DISCORD_WEBHOOK_URL=${{ inputs.discord_webhook_url }} \
146+
LOGTAIL_TOKEN=${{ inputs.logtail_token }} \
143147
REDIS_URL=${{ inputs.redis_url }} \
144148
MAIL_HOST=${{ inputs.mail_host }} \
145149
MAIL_PORT=${{ inputs.mail_port }} \

.github/workflows/build-and-deploy.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ jobs:
9595
cloudflare_api_key: ${{ secrets.CLOUDFLARE_API_TOKEN }}
9696
database_password: ${{ secrets.DATABASE_PASSWORD }}
9797
database_url: ${{ secrets.DATABASE_URL }}
98+
logtail_token: ${{ secrets.LOGTAIL_TOKEN }}
9899
mail_host: ${{ secrets.MAIL_HOST }}
99100
mail_password: ${{ secrets.MAIL_PASSWORD }}
100101
mail_port: ${{ secrets.MAIL_PORT }}
@@ -129,6 +130,7 @@ jobs:
129130
database_password: ${{ secrets.DATABASE_PASSWORD }}
130131
database_url: ${{ secrets.DATABASE_URL }}
131132
discord_webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
133+
logtail_token: ${{ secrets.LOGTAIL_TOKEN }}
132134
mail_host: ${{ secrets.MAIL_HOST }}
133135
mail_password: ${{ secrets.MAIL_PASSWORD }}
134136
mail_port: ${{ secrets.MAIL_PORT }}

apps/backend/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
"license": "ISC",
1515
"dependencies": {
1616
"@dundring/database": "*",
17+
"@logtail/node": "^0.5.4",
18+
"@logtail/winston": "^0.5.4",
1719
"@types/multer": "^1.4.12",
1820
"cors": "^2.8.5",
1921
"dotenv": "^16.4.5",
@@ -23,6 +25,7 @@
2325
"node-fetch": "^2.6.6",
2426
"nodemailer": "^6.9.10",
2527
"redis": "^4.7.0",
28+
"winston": "^3.17.0",
2629
"ws": "^8.18.0"
2730
},
2831
"devDependencies": {

apps/backend/src/logger.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { Logtail } from '@logtail/node';
2+
import { LogtailTransport } from '@logtail/winston';
3+
import winston from 'winston';
4+
5+
require('dotenv').config();
6+
7+
const isProduction = process.env.NODE_ENV === 'production';
8+
const transports = [];
9+
10+
if (isProduction) {
11+
if (process.env.LOGTAIL_TOKEN) {
12+
const logtail = new Logtail(process.env.LOGTAIL_TOKEN, {
13+
endpoint: 'https://s1307406.eu-nbg-2.betterstackdata.com',
14+
});
15+
transports.push(new LogtailTransport(logtail));
16+
}
17+
18+
transports.push(
19+
new winston.transports.Console({
20+
format: winston.format.combine(
21+
winston.format.timestamp(),
22+
winston.format.json()
23+
),
24+
})
25+
);
26+
}
27+
28+
if (!isProduction) {
29+
transports.push(
30+
new winston.transports.Console({
31+
format: winston.format.combine(
32+
winston.format.colorize(),
33+
winston.format.timestamp({ format: 'HH:mm:ss' }),
34+
winston.format.printf(({ timestamp, level, message, ...meta }) => {
35+
const metaString = Object.keys(meta).length
36+
? JSON.stringify(meta, null, 2)
37+
: '';
38+
return `${timestamp} [${level}]: ${message} ${metaString}`;
39+
})
40+
),
41+
})
42+
);
43+
}
44+
45+
export const logger = winston.createLogger({
46+
level: 'debug',
47+
transports,
48+
});

apps/backend/src/redis.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Member, Room, Status, WebSocketResponse } from '@dundring/types';
22
import { error, hours, isSuccess, success } from '@dundring/utils';
33
import { createClient } from 'redis';
44
import * as websocket from './websocket';
5+
import { logger } from './logger';
56

67
require('dotenv').config();
78

@@ -13,10 +14,10 @@ const redisClient = createClient({
1314
});
1415
const redisPublisher = redisClient.duplicate();
1516
const redisSubscriber = redisClient.duplicate();
16-
redisClient.on('error', (err) => console.log('Redis Client Error', err));
17+
redisClient.on('error', (err) => logger.error('Redis Client Error', err));
1718

1819
export const initRedis = async () => {
19-
console.log('Connect redis client');
20+
logger.info('Connect redis client');
2021
await Promise.all([
2122
redisClient.connect(),
2223
redisPublisher.connect(),
@@ -34,7 +35,7 @@ const handleRoomMessage = (rawMessage: string, channelName: string) => {
3435
};
3536

3637
export const createRoom = async (roomId: string, user: Member) => {
37-
console.log(
38+
logger.info(
3839
`[redis]: Create room with id=${roomId} for user=${user.username}`
3940
);
4041
await Promise.all([
@@ -47,7 +48,7 @@ export const joinRoom = async (
4748
roomId: string,
4849
user: Member
4950
): Promise<Status<Room, 'Room not found'>> => {
50-
console.log(`[redis]: Add user=${user.username} to room with id=${roomId}`);
51+
logger.info(`[redis]: Add user=${user.username} to room with id=${roomId}`);
5152
const roomKey = toRoomKey(roomId);
5253
// TODO: Make atomic/transaction
5354
const usersInRoom = await redisClient.lLen(roomKey);
@@ -71,7 +72,7 @@ export const leaveRoom = async (
7172
roomId: string
7273
): Promise<Status<number, 'Room not found'>> => {
7374
const roomKey = toRoomKey(roomId);
74-
console.log(`[redis]: Remove user=${username} from room with id=${roomId}`);
75+
logger.info(`[redis]: Remove user=${username} from room with id=${roomId}`);
7576

7677
await Promise.all([
7778
redisClient.lRem(roomKey, 0, username),

apps/backend/src/server.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import http from 'http';
66
import { initRedis } from './redis';
77
import { initWebsockets } from './websocket';
88
import router from './routes';
9+
import { logger } from './logger';
910

1011
require('dotenv').config();
1112

@@ -56,4 +57,5 @@ initRedis();
5657

5758
httpServer.listen(httpPort, () => {
5859
console.log(`App is listening on port ${httpPort}!:)`);
60+
logger.info(`App is listening on port ${httpPort}!:)`);
5961
});

apps/backend/src/services/groupSessionService.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { generateRandomString, isSuccess } from '@dundring/utils';
1212
import { monitoringService } from '.';
1313
import * as redis from '../redis';
1414
import * as websocket from '../websocket';
15+
import { logger } from '../logger';
1516

1617
export const sendWorkoutDataToRoom = (
1718
username: string,
@@ -69,13 +70,13 @@ export const createRoom = async (
6970
const roomId = await getAvailableRoomId();
7071
console.log('roomId:', roomId);
7172
if (roomId === null) {
72-
console.log(`${user.username} failed to create room.`);
73+
logger.error(`${user.username} failed to create room.`);
7374
return {
7475
type: 'failed-to-create-group-session',
7576
message: 'Failed to create room.',
7677
};
7778
} else {
78-
console.log(
79+
logger.info(
7980
`${user.username} created room #${roomId}. Add to connection pool`
8081
);
8182

@@ -90,7 +91,7 @@ export const createRoom = async (
9091
};
9192

9293
export const joinRoom = async (roomId: string, member: Member) => {
93-
console.log(
94+
logger.info(
9495
`${member.username} tries to join ${roomId}. Add to connection pool`
9596
);
9697
const joinRoomResponse = await redis.joinRoom(roomId, member);

apps/backend/src/websocket.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { WebSocketServer, WebSocket } from 'ws';
33
import { groupSessionService } from './services';
44
import * as redis from './redis';
55
import { error, isSuccess, success } from '@dundring/utils';
6+
import { logger } from './logger';
67

78
const connections: { [username: string]: WebSocket } = {};
89

@@ -44,7 +45,7 @@ export const initWebsockets = (webSocketServer: WebSocketServer) => {
4445
}
4546
case 'send-data': {
4647
if (!username) {
47-
console.log('unknown tried to share workoutdata');
48+
logger.warn('unknown tried to share workoutdata');
4849
return;
4950
}
5051
groupSessionService.sendWorkoutDataToRoom(username, req.data);
@@ -53,7 +54,7 @@ export const initWebsockets = (webSocketServer: WebSocketServer) => {
5354
}
5455
});
5556
ws.on('close', () => {
56-
console.log('connection closed', username);
57+
logger.info('connection closed', username);
5758
if (username && roomId) {
5859
groupSessionService.leaveRoom(username, roomId);
5960
username = '';
@@ -82,7 +83,7 @@ export const sendMessageToRoom = async (
8283
.filter((socket) => socket)
8384
.map((socket) => socket.send(JSON.stringify(message)));
8485
} else {
85-
console.log(`[websocket]: Could not send message to room ${roomId}`);
86+
logger.error(`[websocket]: Could not send message to room ${roomId}`);
8687
}
8788
};
8889

@@ -95,7 +96,7 @@ export const sendMessage = (
9596
socket.send(JSON.stringify(message));
9697
return success({});
9798
} else {
98-
console.log(
99+
logger.error(
99100
`[websocket]: Socket not found for username ${recipientUsername}`
100101
);
101102
return error('Socket not found for username');

docker/deploy/docker-compose.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ services:
2727
- POD=green
2828
- TAG=${TAG_GREEN}
2929
- NODE_ENV=production
30+
- LOGTAIL_TOKEN=${LOGTAIL_TOKEN}
3031
networks:
3132
- caddy
3233
- dundring
@@ -80,6 +81,7 @@ services:
8081
- POD=blue
8182
- TAG=${TAG_BLUE}
8283
- NODE_ENV=production
84+
- LOGTAIL_TOKEN=${LOGTAIL_TOKEN}
8385
networks:
8486
- caddy
8587
- dundring

0 commit comments

Comments
 (0)