Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .env-sample
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,9 @@ GOLDEN_HONEY_BADGER_PROBABILITY=100

# Number of notification messages sent to the admin, informing them of lack of solvers before disabling the community. The admin receives `MAX_ADMIN_WARNINGS_BEFORE_DEACTIVATION - 1` notification messages.
MAX_ADMIN_WARNINGS_BEFORE_DEACTIVATION=10

# The file in which commands will be logged
COMMAND_LOG_FILE='commands.log'

# The maximum size of the command log file in gigabytes
COMMAND_LOG_SIZE_GB=4
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ node_modules
admin.macaroon
tls.cert
dist/
.history/
.history/
commands.log
75 changes: 75 additions & 0 deletions bot/middleware/commandlogging.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { MiddlewareFn } from 'telegraf';
import { CommunityContext } from '../modules/community/communityContext';
import winston from 'winston';

const logFile = process.env.COMMAND_LOG_FILE || 'commands.log';
const maxSizeGB = parseInt(process.env.COMMAND_LOG_SIZE_GB || '5', 10) || 5;

const logger = winston.createLogger({
format: winston.format.combine(
winston.format.timestamp({
format: 'YYYY-MM-DDTHH:mm:ss.SSSZ',
}),
winston.format.printf(info => {
return `[${info.timestamp}] ${info.level}: ${info.message} ${
info.stack ? info.stack : ''
}`;
}),
),
levels: winston.config.syslog.levels,
level: 'debug',
transports: [
new winston.transports.File({
filename: logFile,
maxsize: maxSizeGB * 1024 * 1024 * 1000, // 5GB
}),
],
exitOnError: false,
});

export function commandLogger(): MiddlewareFn<CommunityContext> {
return async (ctx, next) => {
try {
if (ctx.message && 'text' in ctx.message) {
const msg = ctx.message;
const text = msg.text.trim();
const userId = msg.from?.id ?? 'unknown';

let command: string | null = null;
let args: string[] = [];
let isCommand: boolean;

if (text.startsWith('/')) {
const parts = text.split(/\s+/);
command = parts[0];
args = parts.slice(1);
isCommand = true;
} else {
isCommand = false;
command = text;
}

const userName = msg.from?.username ?? '';

logger.info(
`User @${userName} [${userId}] ${isCommand ? 'executed command:' : 'sent message:'} ${command} with args: [${args.join(', ')}]`,
);
} else if (ctx.callbackQuery && 'data' in ctx.callbackQuery) {
// Attempt to get message text
const msgText = (ctx.callbackQuery?.message as any)?.text ?? '';
const callbackData = ctx.callbackQuery.data;
const userName = ctx.callbackQuery.from?.username ?? '';
const userId = ctx.callbackQuery.from?.id ?? '';
logger.info(
`User @${userName} [${userId}] sent callback query with data: ${callbackData}. Message text: '${msgText}'`,
);
} else {
logger.info(`Received non-command message or update from user.`);
}
} catch (err) {
logger.error('logging middleware failed', err);
}

return next();
};
}
2 changes: 2 additions & 0 deletions bot/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ import {
import { logger } from '../logger';
import { IUsernameId } from '../models/community';
import { CommunityContext } from './modules/community/communityContext';
import { commandLogger } from './middleware/commandlogging';

export interface MainContext extends Context {
match: Array<string> | null;
Expand Down Expand Up @@ -192,6 +193,7 @@ const initialize = (
logger.error(err);
});

bot.use(commandLogger());
bot.use(session());
bot.use(limit());
bot.use(i18n.middleware());
Expand Down
7 changes: 0 additions & 7 deletions tests/bot/bot.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -447,13 +447,6 @@ describe('Bot Initialization', () => {
sinon.restore();
});

it('should initialize the bot and register middleware', () => {
initialize('dummy-token', {});

expect(botStub.catch.calledOnce).to.be.equal(true);
expect(botStub.use.callCount).to.be.equal(5);
});

it('should schedule recurring jobs', () => {
process.env.PENDING_PAYMENT_WINDOW = '10';

Expand Down
Loading