diff --git a/packages/backend/scripts/check_connect.js b/packages/backend/scripts/check_connect.js index 5d6d2fca49..edfcce00b0 100644 --- a/packages/backend/scripts/check_connect.js +++ b/packages/backend/scripts/check_connect.js @@ -7,11 +7,6 @@ import Redis from 'ioredis'; import { loadConfig } from '../built/config.js'; import { createPostgresDataSource } from '../built/postgres.js'; -const timeout = setTimeout(() => { - console.error('Timeout while connecting to databases.'); - process.exit(1); -}, 120000); - const config = loadConfig(); async function connectToPostgres() { @@ -59,5 +54,3 @@ const promises = Array ]); await Promise.allSettled(promises); - -clearTimeout(timeout); diff --git a/packages/backend/src/boot/master.ts b/packages/backend/src/boot/master.ts index 551ff984b1..407694792a 100644 --- a/packages/backend/src/boot/master.ts +++ b/packages/backend/src/boot/master.ts @@ -43,6 +43,12 @@ mBuildInfo.set({ node_version: process.version }, 1); +const mStartupTime = new prom.Gauge({ + name: 'misskey_startup_time', + help: 'Misskey startup time', + labelNames: ['pid'] +}); + function greet() { if (!envOption.quiet) { //#region Misskey logo @@ -112,6 +118,8 @@ export async function masterMain() { }); } + mStartupTime.set({ pid: process.pid }, Date.now()); + if (envOption.disableClustering) { if (envOption.onlyServer) { await server(); diff --git a/packages/backend/src/core/QueueModule.ts b/packages/backend/src/core/QueueModule.ts index 3fb05cda3b..e5ab015585 100644 --- a/packages/backend/src/core/QueueModule.ts +++ b/packages/backend/src/core/QueueModule.ts @@ -31,16 +31,18 @@ export type UserWebhookDeliverQueue = Bull.Queue; export type SystemWebhookDeliverQueue = Bull.Queue; function withMetrics(queue: Bull.Queue): Bull.Queue { - setInterval(async () => { - mActiveJobs.set({ queue: queue.name }, await queue.getActiveCount()); - mDelayedJobs.set({ queue: queue.name }, await queue.getDelayedCount()); - mWaitingJobs.set({ queue: queue.name }, await queue.getWaitingCount()); - }, 2000); - - queue.on('waiting', () => { - mJobReceivedCounter.inc({ queue: queue.name }); - }); + if (process.env.NODE_ENV !== 'test') { + setInterval(async () => { + mActiveJobs.set({ queue: queue.name }, await queue.getActiveCount()); + mDelayedJobs.set({ queue: queue.name }, await queue.getDelayedCount()); + mWaitingJobs.set({ queue: queue.name }, await queue.getWaitingCount()); + }, 2000); + queue.on('waiting', () => { + mJobReceivedCounter.inc({ queue: queue.name }); + }); + } + return queue; } diff --git a/packages/backend/src/core/activitypub/ApInboxService.ts b/packages/backend/src/core/activitypub/ApInboxService.ts index a3bd5678d4..564bcb0fa6 100644 --- a/packages/backend/src/core/activitypub/ApInboxService.ts +++ b/packages/backend/src/core/activitypub/ApInboxService.ts @@ -40,16 +40,16 @@ import { ApQuestionService } from './models/ApQuestionService.js'; import type { Resolver } from './ApResolverService.js'; import type { IAccept, IAdd, IAnnounce, IBlock, ICreate, IDelete, IFlag, IFollow, ILike, IObject, IReject, IRemove, IUndo, IUpdate, IMove, IPost } from './type.js'; +const mInboxReceived = new prom.Counter({ + name: 'misskey_ap_inbox_received_total', + help: 'Total number of activities received by AP inbox', + labelNames: ['host', 'type'], +}); + @Injectable() export class ApInboxService { private logger: Logger; - private mInboxReceived = new prom.Counter({ - name: 'misskey_ap_inbox_received_total', - help: 'Total number of activities received by AP inbox', - labelNames: ['host', 'type'], - }); - constructor( @Inject(DI.config) private config: Config, @@ -138,49 +138,49 @@ export class ApInboxService { if (actor.isSuspended) return; if (isCreate(activity)) { - this.mInboxReceived.inc({ host: actor.host, type: 'create' }); + mInboxReceived.inc({ host: actor.host, type: 'create' }); return await this.create(actor, activity); } else if (isDelete(activity)) { - this.mInboxReceived.inc({ host: actor.host, type: 'delete' }); + mInboxReceived.inc({ host: actor.host, type: 'delete' }); return await this.delete(actor, activity); } else if (isUpdate(activity)) { - this.mInboxReceived.inc({ host: actor.host, type: 'update' }); + mInboxReceived.inc({ host: actor.host, type: 'update' }); return await this.update(actor, activity); } else if (isFollow(activity)) { - this.mInboxReceived.inc({ host: actor.host, type: 'follow' }); + mInboxReceived.inc({ host: actor.host, type: 'follow' }); return await this.follow(actor, activity); } else if (isAccept(activity)) { - this.mInboxReceived.inc({ host: actor.host, type: 'accept' }); + mInboxReceived.inc({ host: actor.host, type: 'accept' }); return await this.accept(actor, activity); } else if (isReject(activity)) { - this.mInboxReceived.inc({ host: actor.host, type: 'reject' }); + mInboxReceived.inc({ host: actor.host, type: 'reject' }); return await this.reject(actor, activity); } else if (isAdd(activity)) { - this.mInboxReceived.inc({ host: actor.host, type: 'add' }); + mInboxReceived.inc({ host: actor.host, type: 'add' }); return await this.add(actor, activity); } else if (isRemove(activity)) { - this.mInboxReceived.inc({ host: actor.host, type: 'remove' }); + mInboxReceived.inc({ host: actor.host, type: 'remove' }); return await this.remove(actor, activity); } else if (isAnnounce(activity)) { - this.mInboxReceived.inc({ host: actor.host, type: 'announce' }); + mInboxReceived.inc({ host: actor.host, type: 'announce' }); return await this.announce(actor, activity); } else if (isLike(activity)) { - this.mInboxReceived.inc({ host: actor.host, type: 'like' }); + mInboxReceived.inc({ host: actor.host, type: 'like' }); return await this.like(actor, activity); } else if (isUndo(activity)) { - this.mInboxReceived.inc({ host: actor.host, type: 'undo' }); + mInboxReceived.inc({ host: actor.host, type: 'undo' }); return await this.undo(actor, activity); } else if (isBlock(activity)) { - this.mInboxReceived.inc({ host: actor.host, type: 'block' }); + mInboxReceived.inc({ host: actor.host, type: 'block' }); return await this.block(actor, activity); } else if (isFlag(activity)) { - this.mInboxReceived.inc({ host: actor.host, type: 'flag' }); + mInboxReceived.inc({ host: actor.host, type: 'flag' }); return await this.flag(actor, activity); } else if (isMove(activity)) { - this.mInboxReceived.inc({ host: actor.host, type: 'move' }); + mInboxReceived.inc({ host: actor.host, type: 'move' }); return await this.move(actor, activity); } else { - this.mInboxReceived.inc({ host: actor.host, type: 'unknown' }); + mInboxReceived.inc({ host: actor.host, type: 'unknown' }); return `unrecognized activity type: ${activity.type}`; } } diff --git a/packages/backend/src/postgres.ts b/packages/backend/src/postgres.ts index 6fce6a6faa..ca1cb2a175 100644 --- a/packages/backend/src/postgres.ts +++ b/packages/backend/src/postgres.ts @@ -341,8 +341,8 @@ export function createPostgresDataSource(config: Config, isMain = false) { db: config.redis.db ?? 0, }, } : false, - logging: log ? 'all' : ['query'], - logger: (isMain || log) ? new MyCustomLogger(!log) : undefined, + logging: true, + logger: new MyCustomLogger(!log), maxQueryExecutionTime: 500, entities: entities, migrations: ['../../migration/*.js'], diff --git a/packages/backend/src/queue/processors/InboxProcessorService.ts b/packages/backend/src/queue/processors/InboxProcessorService.ts index bd6da6c668..12b76081af 100644 --- a/packages/backend/src/queue/processors/InboxProcessorService.ts +++ b/packages/backend/src/queue/processors/InboxProcessorService.ts @@ -38,42 +38,42 @@ type UpdateInstanceJob = { shouldUnsuspend: boolean, }; +const mIncomingApProcessingTime = new prom.Histogram({ + name: 'misskey_incoming_ap_processing_time', + help: 'Incoming AP processing time in seconds', + labelNames: ['incoming_host', 'incoming_type', 'success'], + buckets: [0.01, 0.1, 0.5, 1, 5, 10, 30, 60, 300, 1800], +}); + +const mIncomingApEvent = new prom.Counter({ + name: 'misskey_incoming_ap_event', + help: 'Incoming AP event', + labelNames: ['incoming_host', 'incoming_type'], +}); + +const mIncomingApEventAccepted = new prom.Counter({ + name: 'misskey_incoming_ap_event_accepted', + help: 'Incoming AP event accepted', + labelNames: ['incoming_host', 'incoming_type'], +}); + +const mIncomingApReject = new prom.Counter({ + name: 'misskey_incoming_ap_reject', + help: 'Incoming AP reject', + labelNames: ['incoming_host', 'incoming_type', 'reason'], +}); + +const mincomingApProcessingError = new prom.Counter({ + name: 'misskey_incoming_ap_processing_error', + help: 'Incoming AP processing error', + labelNames: ['incoming_host', 'incoming_type'], +}); + @Injectable() export class InboxProcessorService implements OnApplicationShutdown { private logger: Logger; private updateInstanceQueue: CollapsedQueue; - private mIncomingApProcessingTime = new prom.Histogram({ - name: 'misskey_incoming_ap_processing_time', - help: 'Incoming AP processing time in seconds', - labelNames: ['incoming_host', 'incoming_type', 'success'], - buckets: [0.01, 0.1, 0.5, 1, 5, 10, 30, 60, 300, 1800], - }); - - private mIncomingApEvent = new prom.Counter({ - name: 'misskey_incoming_ap_event', - help: 'Incoming AP event', - labelNames: ['incoming_host', 'incoming_type'], - }); - - private mIncomingApEventAccepted = new prom.Counter({ - name: 'misskey_incoming_ap_event_accepted', - help: 'Incoming AP event accepted', - labelNames: ['incoming_host', 'incoming_type'], - }); - - private mIncomingApReject = new prom.Counter({ - name: 'misskey_incoming_ap_reject', - help: 'Incoming AP reject', - labelNames: ['incoming_host', 'incoming_type', 'reason'], - }); - - private mincomingApProcessingError = new prom.Counter({ - name: 'misskey_incoming_ap_processing_error', - help: 'Incoming AP processing error', - labelNames: ['incoming_host', 'incoming_type'], - }); - constructor( @Inject(DI.meta) private meta: MiMeta, @@ -127,13 +127,13 @@ export class InboxProcessorService implements OnApplicationShutdown { }; if (!this.utilityService.isFederationAllowedHost(host)) { - incCounter(this.mIncomingApReject, { reason: 'host_not_allowed' }); + incCounter(mIncomingApReject, { reason: 'host_not_allowed' }); return `Blocked request: ${host}`; } const keyIdLower = signature.keyId.toLowerCase(); if (keyIdLower.startsWith('acct:')) { - incCounter(this.mIncomingApReject, { reason: 'keyid_acct' }); + incCounter(mIncomingApReject, { reason: 'keyid_acct' }); return `Old keyId is no longer supported. ${keyIdLower}`; } @@ -151,7 +151,7 @@ export class InboxProcessorService implements OnApplicationShutdown { // 対象が4xxならスキップ if (err instanceof StatusError) { if (!err.isRetryable) { - incCounter(this.mIncomingApReject, { reason: 'actor_key_unresolvable' }); + incCounter(mIncomingApReject, { reason: 'actor_key_unresolvable' }); throw new Bull.UnrecoverableError(`skip: Ignored deleted actors on both ends ${activity.actor} - ${err.statusCode}`); } throw new Error(`Error in actor ${activity.actor} - ${err.statusCode}`); @@ -161,13 +161,13 @@ export class InboxProcessorService implements OnApplicationShutdown { // それでもわからなければ終了 if (authUser == null) { - incCounter(this.mIncomingApReject, { reason: 'actor_unresolvable' }); + incCounter(mIncomingApReject, { reason: 'actor_unresolvable' }); throw new Bull.UnrecoverableError('skip: failed to resolve user'); } // publicKey がなくても終了 if (authUser.key == null) { - incCounter(this.mIncomingApReject, { reason: 'publickey_unresolvable' }); + incCounter(mIncomingApReject, { reason: 'publickey_unresolvable' }); throw new Bull.UnrecoverableError('skip: failed to resolve user publicKey'); } @@ -180,7 +180,7 @@ export class InboxProcessorService implements OnApplicationShutdown { const ldSignature = activity.signature; if (ldSignature) { if (ldSignature.type !== 'RsaSignature2017') { - incCounter(this.mIncomingApReject, { reason: 'ld_signature_unsupported' }); + incCounter(mIncomingApReject, { reason: 'ld_signature_unsupported' }); throw new Bull.UnrecoverableError(`skip: unsupported LD-signature type ${ldSignature.type}`); } @@ -194,12 +194,12 @@ export class InboxProcessorService implements OnApplicationShutdown { // keyIdからLD-Signatureのユーザーを取得 authUser = await this.apDbResolverService.getAuthUserFromKeyId(ldSignature.creator); if (authUser == null) { - incCounter(this.mIncomingApReject, { reason: 'ld_signature_user_unresolvable' }); + incCounter(mIncomingApReject, { reason: 'ld_signature_user_unresolvable' }); throw new Bull.UnrecoverableError('skip: LD-Signatureのユーザーが取得できませんでした'); } if (authUser.key == null) { - incCounter(this.mIncomingApReject, { reason: 'ld_signature_publickey_unavailable' }); + incCounter(mIncomingApReject, { reason: 'ld_signature_publickey_unavailable' }); throw new Bull.UnrecoverableError('skip: LD-SignatureのユーザーはpublicKeyを持っていませんでした'); } @@ -208,7 +208,7 @@ export class InboxProcessorService implements OnApplicationShutdown { // LD-Signature検証 const verified = await jsonLd.verifyRsaSignature2017(activity, authUser.key.keyPem).catch(() => false); if (!verified) { - incCounter(this.mIncomingApReject, { reason: 'ld_signature_verification_failed' }); + incCounter(mIncomingApReject, { reason: 'ld_signature_verification_failed' }); throw new Bull.UnrecoverableError('skip: LD-Signatureの検証に失敗しました'); } @@ -231,17 +231,17 @@ export class InboxProcessorService implements OnApplicationShutdown { // もう一度actorチェック if (authUser.user.uri !== activity.actor) { - incCounter(this.mIncomingApReject, { reason: 'ld_signature_actor_mismatch' }); + incCounter(mIncomingApReject, { reason: 'ld_signature_actor_mismatch' }); throw new Bull.UnrecoverableError(`skip: LD-Signature user(${authUser.user.uri}) !== activity.actor(${activity.actor})`); } const ldHost = this.utilityService.extractDbHost(authUser.user.uri); if (!this.utilityService.isFederationAllowedHost(ldHost)) { - incCounter(this.mIncomingApReject, { reason: 'fed_host_not_allowed' }); + incCounter(mIncomingApReject, { reason: 'fed_host_not_allowed' }); throw new Bull.UnrecoverableError(`Blocked request: ${ldHost}`); } } else { - incCounter(this.mIncomingApReject, { reason: 'ld_signature_unavailable' }); + incCounter(mIncomingApReject, { reason: 'ld_signature_unavailable' }); throw new Bull.UnrecoverableError(`skip: http-signature verification failed and no LD-Signature. keyId=${signature.keyId}`); } } @@ -251,7 +251,7 @@ export class InboxProcessorService implements OnApplicationShutdown { const signerHost = this.utilityService.extractDbHost(authUser.user.uri!); const activityIdHost = this.utilityService.extractDbHost(activity.id); if (signerHost !== activityIdHost) { - incCounter(this.mIncomingApReject, 'host_signature_mismatch'); + incCounter(mIncomingApReject, 'host_signature_mismatch'); throw new Bull.UnrecoverableError(`skip: signerHost(${signerHost}) !== activity.id host(${activityIdHost}`); } } @@ -279,7 +279,7 @@ export class InboxProcessorService implements OnApplicationShutdown { this.fetchInstanceMetadataService.fetchInstanceMetadata(i); }); - incCounter(this.mIncomingApEvent, {}); + incCounter(mIncomingApEvent, {}); // アクティビティを処理 const begin = +new Date(); @@ -292,25 +292,25 @@ export class InboxProcessorService implements OnApplicationShutdown { } catch (e) { if (e instanceof IdentifiableError) { if (e.id === '689ee33f-f97c-479a-ac49-1b9f8140af99') { - incCounter(this.mIncomingApReject, { reason: 'blocked_notes_with_prohibited_words' }); + incCounter(mIncomingApReject, { reason: 'blocked_notes_with_prohibited_words' }); return 'blocked notes with prohibited words'; } if (e.id === '85ab9bd7-3a41-4530-959d-f07073900109') { - incCounter(this.mIncomingApReject, { reason: 'actor_suspended' }); + incCounter(mIncomingApReject, { reason: 'actor_suspended' }); return 'actor has been suspended'; } if (e.id === 'd450b8a9-48e4-4dab-ae36-f4db763fda7c') { // invalid Note - incCounter(this.mIncomingApReject, { reason: 'invalid_note' }); + incCounter(mIncomingApReject, { reason: 'invalid_note' }); return e.message; } } const end = +new Date(); - observeHistogram(this.mIncomingApProcessingTime, { success: 'false' }, (end - begin) / 1000); - incCounter(this.mincomingApProcessingError, { reason: 'unknown' }); + observeHistogram(mIncomingApProcessingTime, { success: 'false' }, (end - begin) / 1000); + incCounter(mincomingApProcessingError, { reason: 'unknown' }); throw e; } - observeHistogram(this.mIncomingApProcessingTime, { success: 'true' }, (+new Date() - begin) / 1000); - incCounter(this.mIncomingApEventAccepted, {}); + observeHistogram(mIncomingApProcessingTime, { success: 'true' }, (+new Date() - begin) / 1000); + incCounter(mIncomingApEventAccepted, {}); return 'ok'; } diff --git a/packages/backend/src/server/ServerService.ts b/packages/backend/src/server/ServerService.ts index bbb0503c1e..e908375786 100644 --- a/packages/backend/src/server/ServerService.ts +++ b/packages/backend/src/server/ServerService.ts @@ -55,66 +55,66 @@ function categorizeRequestPath(path: string): 'api' | 'health' | 'vite' | 'other return 'other'; } +const mRequestTime = new prom.Histogram({ + name: 'misskey_http_request_duration_seconds', + help: 'Duration of handling HTTP requests in seconds', + labelNames: ['host', 'cate', 'method', 'path'], + buckets: [0.001, 0.1, 0.5, 1, 2, 5], +}); + +const mRequestsReceived = new prom.Counter({ + name: 'misskey_http_requests_received_total', + help: 'Total number of HTTP requests received', + labelNames: [], +}); + +const mNotFoundServed = new prom.Counter({ + name: 'misskey_http_not_found_served_total', + help: 'Total number of HTTP 404 responses served', + labelNames: ['method', 'cate'], +}); + +const mMethodNotAllowedServed = new prom.Counter({ + name: 'misskey_http_method_not_allowed_served_total', + help: 'Total number of HTTP 405 responses served', + labelNames: ['method', 'cate'], +}); + +const mTooManyRequestsServed = new prom.Counter({ + name: 'misskey_http_too_many_requests_served_total', + help: 'Total number of HTTP 429 responses served', + labelNames: ['method', 'cate'], +}); + +const mAggregateRequestsServed = new prom.Counter({ + name: 'misskey_http_requests_served_total', + help: 'Total number of HTTP requests served including invalid requests', + labelNames: ['host', 'cate', 'status'], +}); + +const mRequestsServedByPath = new prom.Counter({ + name: 'misskey_http_requests_served_by_path', + help: 'Total number of HTTP requests served', + labelNames: ['host', 'cate', 'method', 'path', 'status'], +}); + +const mFatalErrorCount = new prom.Counter({ + name: 'misskey_fatal_http_errors_total', + help: 'Total number of HTTP errors that propagate to the top level', + labelNames: ['host', 'cate', 'method', 'path'], +}); + +const mLastSuccessfulRequest = new prom.Gauge({ + name: 'misskey_http_last_successful_request_timestamp_seconds', + help: 'Unix Timestamp of the last successful HTTP request', + labelNames: [], +}); + @Injectable() export class ServerService implements OnApplicationShutdown { private logger: Logger; #fastify: FastifyInstance; - private mRequestTime = new prom.Histogram({ - name: 'misskey_http_request_duration_seconds', - help: 'Duration of handling HTTP requests in seconds', - labelNames: ['host', 'cate', 'method', 'path'], - buckets: [0.001, 0.1, 0.5, 1, 2, 5], - }); - - private mRequestsReceived = new prom.Counter({ - name: 'misskey_http_requests_received_total', - help: 'Total number of HTTP requests received', - labelNames: [], - }); - - private mNotFoundServed = new prom.Counter({ - name: 'misskey_http_not_found_served_total', - help: 'Total number of HTTP 404 responses served', - labelNames: ['method', 'cate'], - }); - - private mMethodNotAllowedServed = new prom.Counter({ - name: 'misskey_http_method_not_allowed_served_total', - help: 'Total number of HTTP 405 responses served', - labelNames: ['method', 'cate'], - }); - - private mTooManyRequestsServed = new prom.Counter({ - name: 'misskey_http_too_many_requests_served_total', - help: 'Total number of HTTP 429 responses served', - labelNames: ['method', 'cate'], - }); - - private mAggregateRequestsServed = new prom.Counter({ - name: 'misskey_http_requests_served_total', - help: 'Total number of HTTP requests served including invalid requests', - labelNames: ['host', 'cate', 'status'], - }); - - private mRequestsServedByPath = new prom.Counter({ - name: 'misskey_http_requests_served_by_path', - help: 'Total number of HTTP requests served', - labelNames: ['host', 'cate', 'method', 'path', 'status'], - }); - - private mFatalErrorCount = new prom.Counter({ - name: 'misskey_fatal_http_errors_total', - help: 'Total number of HTTP errors that propagate to the top level', - labelNames: ['host', 'cate', 'method', 'path'], - }); - - private mLastSuccessfulRequest = new prom.Gauge({ - name: 'misskey_http_last_successful_request_timestamp_seconds', - help: 'Unix Timestamp of the last successful HTTP request', - labelNames: [], - }); - constructor( @Inject(DI.config) private config: Config, @@ -160,14 +160,14 @@ export class ServerService implements OnApplicationShutdown { if (this.config.prometheusMetrics?.enable) { fastify.addHook('onRequest', (_request, reply, done) => { reply.header('x-request-received', (+new Date()).toString()); - this.mRequestsReceived.inc(); + mRequestsReceived.inc(); done(); }); fastify.addHook('onError', (request, _reply, error, done) => { const url = new URL(request.url, this.config.url); const logPath = sanitizeRequestURI(url.pathname); - this.mFatalErrorCount.inc({ + mFatalErrorCount.inc({ host: request.hostname, method: request.method, path: logPath, @@ -182,14 +182,14 @@ export class ServerService implements OnApplicationShutdown { const cate = categorizeRequestPath(logPath); const received = reply.getHeader('x-request-received') as string; - this.mAggregateRequestsServed.inc({ + mAggregateRequestsServed.inc({ host: request.hostname, cate, status: reply.statusCode, }); if (reply.statusCode === 429) { - this.mTooManyRequestsServed.inc({ + mTooManyRequestsServed.inc({ method: request.method, cate, }); @@ -199,14 +199,14 @@ export class ServerService implements OnApplicationShutdown { } if (reply.statusCode === 404) { - this.mNotFoundServed.inc({ + mNotFoundServed.inc({ method: request.method, cate, }); if (received) { const duration = (+new Date()) - parseInt(received); - this.mRequestTime.observe({ + mRequestTime.observe({ host: request.hostname, method: request.method, cate, @@ -218,7 +218,7 @@ export class ServerService implements OnApplicationShutdown { } if (reply.statusCode === 405) { - this.mMethodNotAllowedServed.inc({ + mMethodNotAllowedServed.inc({ method: request.method, cate, }); @@ -229,7 +229,7 @@ export class ServerService implements OnApplicationShutdown { if (received) { const duration = (+new Date()) - parseInt(received); - this.mRequestTime.observe({ + mRequestTime.observe({ host: request.hostname, method: request.method, cate, @@ -243,10 +243,10 @@ export class ServerService implements OnApplicationShutdown { } if (reply.statusCode <= 299) { - this.mLastSuccessfulRequest.set(+new Date() / 1000); + mLastSuccessfulRequest.set(+new Date() / 1000); } - this.mRequestsServedByPath.inc({ + mRequestsServedByPath.inc({ host: request.hostname, method: request.method, path: logPath, diff --git a/packages/backend/src/server/api/AuthenticateService.ts b/packages/backend/src/server/api/AuthenticateService.ts index 13a51e3797..be75607a94 100644 --- a/packages/backend/src/server/api/AuthenticateService.ts +++ b/packages/backend/src/server/api/AuthenticateService.ts @@ -22,16 +22,16 @@ export class AuthenticationError extends Error { } } +const mAuthenticationFailureCounter = new prom.Counter({ + name: 'misskey_authentication_failure_total', + help: 'Total number of authentication failures', + labelNames: ['cred_ty'], +}); + @Injectable() export class AuthenticateService implements OnApplicationShutdown { private appCache: MemoryKVCache; - private mAuthenticationFailureCounter = new prom.Counter({ - name: 'misskey_authentication_failure_total', - help: 'Total number of authentication failures', - labelNames: ['cred_ty'], - }); - constructor( @Inject(DI.usersRepository) private usersRepository: UsersRepository, @@ -58,7 +58,7 @@ export class AuthenticateService implements OnApplicationShutdown { () => this.usersRepository.findOneBy({ token }) as Promise); if (user == null) { - this.mAuthenticationFailureCounter.inc({ cred_ty: 'native' }); + mAuthenticationFailureCounter.inc({ cred_ty: 'native' }); throw new AuthenticationError('user not found'); } @@ -73,7 +73,7 @@ export class AuthenticateService implements OnApplicationShutdown { }); if (accessToken == null) { - this.mAuthenticationFailureCounter.inc({ cred_ty: 'access_token' }); + mAuthenticationFailureCounter.inc({ cred_ty: 'access_token' }); throw new AuthenticationError('invalid signature'); } diff --git a/packages/backend/src/server/api/SigninApiService.ts b/packages/backend/src/server/api/SigninApiService.ts index 80cfdf5436..01fc8fd62a 100644 --- a/packages/backend/src/server/api/SigninApiService.ts +++ b/packages/backend/src/server/api/SigninApiService.ts @@ -30,14 +30,14 @@ import { SigninService } from './SigninService.js'; import type { AuthenticationResponseJSON } from '@simplewebauthn/types'; import type { FastifyReply, FastifyRequest } from 'fastify'; +const mSigninFailureCounter = new prom.Counter({ + name: 'misskey_misskey_signin_failure', + help: 'The number of failed sign-ins', + labelNames: ['reason'], +}); + @Injectable() export class SigninApiService { - private mSigninFailureCounter = new prom.Counter({ - name: 'misskey_misskey_signin_failure', - help: 'The number of failed sign-ins', - labelNames: ['reason'], - }); - constructor( @Inject(DI.config) private config: Config, @@ -100,7 +100,7 @@ export class SigninApiService { // not more than 1 attempt per second and not more than 10 attempts per hour await this.rateLimiterService.limit({ key: 'signin', duration: 60 * 60 * 1000, max: 10, minInterval: 1000 }, getIpHash(request.ip)); } catch (err) { - this.mSigninFailureCounter.inc({ reason: 'rate_limit' }); + mSigninFailureCounter.inc({ reason: 'rate_limit' }); reply.code(429); return { error: { @@ -112,13 +112,13 @@ export class SigninApiService { } if (typeof username !== 'string') { - this.mSigninFailureCounter.inc({ reason: 'bad_form' }); + mSigninFailureCounter.inc({ reason: 'bad_form' }); reply.code(400); return; } if (token != null && typeof token !== 'string') { - this.mSigninFailureCounter.inc({ reason: 'bad_form' }); + mSigninFailureCounter.inc({ reason: 'bad_form' }); reply.code(400); return; } @@ -130,14 +130,14 @@ export class SigninApiService { }) as MiLocalUser; if (user == null) { - this.mSigninFailureCounter.inc({ reason: 'user_not_found' }); + mSigninFailureCounter.inc({ reason: 'user_not_found' }); return error(404, { id: '6cc579cc-885d-43d8-95c2-b8c7fc963280', }); } if (user.isSuspended) { - this.mSigninFailureCounter.inc({ reason: 'user_suspended' }); + mSigninFailureCounter.inc({ reason: 'user_suspended' }); return error(403, { id: 'e03a5f46-d309-4865-9b69-56282d94e1eb', }); @@ -162,7 +162,7 @@ export class SigninApiService { } if (typeof password !== 'string') { - this.mSigninFailureCounter.inc({ reason: 'bad_form' }); + mSigninFailureCounter.inc({ reason: 'bad_form' }); reply.code(400); return; } @@ -180,7 +180,7 @@ export class SigninApiService { success: false, }); - this.mSigninFailureCounter.inc({ reason: failure?.id ?? `unknown_error_${status ?? 500}` }); + mSigninFailureCounter.inc({ reason: failure?.id ?? `unknown_error_${status ?? 500}` }); return error(status ?? 500, failure ?? { id: '4e30e80c-e338-45a0-8c8f-44455efa3b76' }); }; @@ -188,35 +188,35 @@ export class SigninApiService { if (process.env.NODE_ENV !== 'test') { if (this.meta.enableHcaptcha && this.meta.hcaptchaSecretKey) { await this.captchaService.verifyHcaptcha(this.meta.hcaptchaSecretKey, body['hcaptcha-response']).catch(err => { - this.mSigninFailureCounter.inc({ reason: 'captcha_verification_failed_hcaptcha' }); + mSigninFailureCounter.inc({ reason: 'captcha_verification_failed_hcaptcha' }); throw new FastifyReplyError(400, err); }); } if (this.meta.enableMcaptcha && this.meta.mcaptchaSecretKey && this.meta.mcaptchaSitekey && this.meta.mcaptchaInstanceUrl) { await this.captchaService.verifyMcaptcha(this.meta.mcaptchaSecretKey, this.meta.mcaptchaSitekey, this.meta.mcaptchaInstanceUrl, body['m-captcha-response']).catch(err => { - this.mSigninFailureCounter.inc({ reason: 'captcha_verification_failed_mcaptcha' }); + mSigninFailureCounter.inc({ reason: 'captcha_verification_failed_mcaptcha' }); throw new FastifyReplyError(400, err); }); } if (this.meta.enableRecaptcha && this.meta.recaptchaSecretKey) { await this.captchaService.verifyRecaptcha(this.meta.recaptchaSecretKey, body['g-recaptcha-response']).catch(err => { - this.mSigninFailureCounter.inc({ reason: 'captcha_verification_failed_recaptcha' }); + mSigninFailureCounter.inc({ reason: 'captcha_verification_failed_recaptcha' }); throw new FastifyReplyError(400, err); }); } if (this.meta.enableTurnstile && this.meta.turnstileSecretKey) { await this.captchaService.verifyTurnstile(this.meta.turnstileSecretKey, body['turnstile-response']).catch(err => { - this.mSigninFailureCounter.inc({ reason: 'captcha_verification_failed_turnstile' }); + mSigninFailureCounter.inc({ reason: 'captcha_verification_failed_turnstile' }); throw new FastifyReplyError(400, err); }); } if (this.meta.enableTestcaptcha) { await this.captchaService.verifyTestcaptcha(body['testcaptcha-response']).catch(err => { - this.mSigninFailureCounter.inc({ reason: 'captcha_verification_failed_testcaptcha' }); + mSigninFailureCounter.inc({ reason: 'captcha_verification_failed_testcaptcha' }); throw new FastifyReplyError(400, err); }); } diff --git a/packages/backend/test-server/entry.ts b/packages/backend/test-server/entry.ts index 04bf62d209..a6266e3440 100644 --- a/packages/backend/test-server/entry.ts +++ b/packages/backend/test-server/entry.ts @@ -5,7 +5,6 @@ import { NestFactory } from '@nestjs/core'; import { MainModule } from '@/MainModule.js'; import { ServerService } from '@/server/ServerService.js'; import { loadConfig } from '@/config.js'; -import { NestLogger } from '@/NestLogger.js'; import { INestApplicationContext } from '@nestjs/common'; const config = loadConfig(); @@ -22,10 +21,8 @@ let serverService: ServerService; async function launch() { await killTestServer(); - console.log('starting application...'); - app = await NestFactory.createApplicationContext(MainModule, { - logger: new NestLogger(), + logger: ["debug", "log", "error", "warn", "verbose"], }); serverService = app.get(ServerService); await serverService.launch(); @@ -84,7 +81,7 @@ async function startControllerEndpoints(port = config.port + 1000) { console.log('starting application...'); app = await NestFactory.createApplicationContext(MainModule, { - logger: new NestLogger(), + logger: ["debug", "log", "error", "warn", "verbose"], }); serverService = app.get(ServerService); await serverService.launch();