Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 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
7 changes: 7 additions & 0 deletions .env-sample
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,10 @@ 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. It can be both an absolute or relative path (realative to the directory in which your run `npm start`)
COMMAND_LOG_FILE='commands.log'
# The maximum size of each command log file in megabytes
COMMAND_LOG_SIZE_MB=4
# The maximum number of log files to keep
MAX_LOG_FILES=5
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
89 changes: 89 additions & 0 deletions bot/middleware/commandlogging.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { MiddlewareFn } from 'telegraf';
import { CommunityContext } from '../modules/community/communityContext';
import winston from 'winston';
import { extractId } from '../../util';

const logFile = process.env.COMMAND_LOG_FILE || 'commands.log';
const maxSizeMB = parseInt(process.env.COMMAND_LOG_SIZE_MB || '5', 10) || 5;
const maxFiles = parseInt(process.env.MAX_LOG_FILES || '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: maxSizeMB * 1024 ** 2, // maxsize in MB
maxFiles: maxFiles,

Check warning on line 27 in bot/middleware/commandlogging.ts

View workflow job for this annotation

GitHub Actions / Lint

Expected property shorthand
tailable: true,
zippedArchive: false
}),
],
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 callbackQueryMessage =
(ctx.callbackQuery?.message as any)?.text ?? '';
const isId = /^[a-f0-9]{24}$/.test(callbackQueryMessage);
const orderId = isId
? callbackQueryMessage
: extractId(callbackQueryMessage);
const msgText = orderId
? `Order ID: ${orderId}`
: `Message text: '${callbackQueryMessage}'`;
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}. '${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