diff --git a/packages/backend/src/core/QueueService.ts b/packages/backend/src/core/QueueService.ts index 06170b242a..4be568b334 100644 --- a/packages/backend/src/core/QueueService.ts +++ b/packages/backend/src/core/QueueService.ts @@ -810,6 +810,13 @@ export class QueueService { } } + @bindThis + public async queueGetJobLogs(queueType: typeof QUEUE_TYPES[number], jobId: string) { + const queue = this.getQueue(queueType); + const result = await queue.getJobLogs(jobId); + return result.logs; + } + @bindThis public async queueGetJobs(queueType: typeof QUEUE_TYPES[number], jobTypes: JobType[], search?: string) { const RETURN_LIMIT = 100; diff --git a/packages/backend/src/server/api/endpoint-list.ts b/packages/backend/src/server/api/endpoint-list.ts index 5c4a58a6fc..c0c43dd5c9 100644 --- a/packages/backend/src/server/api/endpoint-list.ts +++ b/packages/backend/src/server/api/endpoint-list.ts @@ -70,6 +70,7 @@ export * as 'admin/queue/inbox-delayed' from './endpoints/admin/queue/inbox-dela export * as 'admin/queue/retry-job' from './endpoints/admin/queue/retry-job.js'; export * as 'admin/queue/remove-job' from './endpoints/admin/queue/remove-job.js'; export * as 'admin/queue/show-job' from './endpoints/admin/queue/show-job.js'; +export * as 'admin/queue/show-job-logs' from './endpoints/admin/queue/show-job-logs.js'; export * as 'admin/queue/promote-jobs' from './endpoints/admin/queue/promote-jobs.js'; export * as 'admin/queue/jobs' from './endpoints/admin/queue/jobs.js'; export * as 'admin/queue/stats' from './endpoints/admin/queue/stats.js'; diff --git a/packages/backend/src/server/api/endpoints/admin/queue/show-job-logs.ts b/packages/backend/src/server/api/endpoints/admin/queue/show-job-logs.ts new file mode 100644 index 0000000000..b9292ed12a --- /dev/null +++ b/packages/backend/src/server/api/endpoints/admin/queue/show-job-logs.ts @@ -0,0 +1,45 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { QUEUE_TYPES, QueueService } from '@/core/QueueService.js'; + +export const meta = { + tags: ['admin'], + + requireCredential: true, + requireModerator: true, + kind: 'read:admin:queue', + + res: { + type: 'array', + optional: false, nullable: false, + items: { + optional: false, nullable: false, + type: 'string', + }, + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + queue: { type: 'string', enum: QUEUE_TYPES }, + jobId: { type: 'string' }, + }, + required: ['queue', 'jobId'], +} as const; + +@Injectable() +export default class extends Endpoint { // eslint-disable-line import/no-default-export + constructor( + private queueService: QueueService, + ) { + super(meta, paramDef, async (ps, me) => { + return this.queueService.queueGetJobLogs(ps.queue, ps.jobId); + }); + } +} diff --git a/packages/frontend/src/pages/admin/job-queue.job.vue b/packages/frontend/src/pages/admin/job-queue.job.vue index 4ecdb74199..f96830e57a 100644 --- a/packages/frontend/src/pages/admin/job-queue.job.vue +++ b/packages/frontend/src/pages/admin/job-queue.job.vue @@ -155,6 +155,10 @@ SPDX-License-Identifier: AGPL-3.0-only
+
+ Load logs +
{{ log }}
+
@@ -198,6 +202,7 @@ const emit = defineEmits<{ const tab = ref('info'); const editData = ref(JSON5.stringify(props.job.data, null, '\t')); const canEdit = true; +const logs = ref([]); type TlType = TlEvent<{ type: 'created' | 'processed' | 'finished'; @@ -268,6 +273,10 @@ async function removeJob() { os.apiWithDialog('admin/queue/remove-job', { queue: props.queueType, jobId: props.job.id }); } +async function loadLogs() { + logs.value = await os.apiWithDialog('admin/queue/show-job-logs', { queue: props.queueType, jobId: props.job.id }); +} + // TODO // function moveJob() { // diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index 4ed1c3629f..ae12547f35 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -296,6 +296,12 @@ type AdminQueueRemoveJobRequest = operations['admin___queue___remove-job']['requ // @public (undocumented) type AdminQueueRetryJobRequest = operations['admin___queue___retry-job']['requestBody']['content']['application/json']; +// @public (undocumented) +type AdminQueueShowJobLogsRequest = operations['admin___queue___show-job-logs']['requestBody']['content']['application/json']; + +// @public (undocumented) +type AdminQueueShowJobLogsResponse = operations['admin___queue___show-job-logs']['responses']['200']['content']['application/json']; + // @public (undocumented) type AdminQueueShowJobRequest = operations['admin___queue___show-job']['requestBody']['content']['application/json']; @@ -1559,6 +1565,8 @@ declare namespace entities { AdminQueueRetryJobRequest, AdminQueueShowJobRequest, AdminQueueShowJobResponse, + AdminQueueShowJobLogsRequest, + AdminQueueShowJobLogsResponse, AdminQueueStatsResponse, AdminRelaysAddRequest, AdminRelaysAddResponse, diff --git a/packages/misskey-js/src/autogen/apiClientJSDoc.ts b/packages/misskey-js/src/autogen/apiClientJSDoc.ts index 4a13045592..5407b7a653 100644 --- a/packages/misskey-js/src/autogen/apiClientJSDoc.ts +++ b/packages/misskey-js/src/autogen/apiClientJSDoc.ts @@ -713,6 +713,17 @@ declare module '../api.js' { credential?: string | null, ): Promise>; + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:queue* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + /** * No description provided. * diff --git a/packages/misskey-js/src/autogen/endpoint.ts b/packages/misskey-js/src/autogen/endpoint.ts index 5ef493946c..d7cb2a46eb 100644 --- a/packages/misskey-js/src/autogen/endpoint.ts +++ b/packages/misskey-js/src/autogen/endpoint.ts @@ -88,6 +88,8 @@ import type { AdminQueueRetryJobRequest, AdminQueueShowJobRequest, AdminQueueShowJobResponse, + AdminQueueShowJobLogsRequest, + AdminQueueShowJobLogsResponse, AdminQueueStatsResponse, AdminRelaysAddRequest, AdminRelaysAddResponse, @@ -717,6 +719,7 @@ export type Endpoints = { 'admin/queue/remove-job': { req: AdminQueueRemoveJobRequest; res: EmptyResponse }; 'admin/queue/retry-job': { req: AdminQueueRetryJobRequest; res: EmptyResponse }; 'admin/queue/show-job': { req: AdminQueueShowJobRequest; res: AdminQueueShowJobResponse }; + 'admin/queue/show-job-logs': { req: AdminQueueShowJobLogsRequest; res: AdminQueueShowJobLogsResponse }; 'admin/queue/stats': { req: EmptyRequest; res: AdminQueueStatsResponse }; 'admin/relays/add': { req: AdminRelaysAddRequest; res: AdminRelaysAddResponse }; 'admin/relays/list': { req: EmptyRequest; res: AdminRelaysListResponse }; diff --git a/packages/misskey-js/src/autogen/entities.ts b/packages/misskey-js/src/autogen/entities.ts index a11bbefde5..a14febb6e6 100644 --- a/packages/misskey-js/src/autogen/entities.ts +++ b/packages/misskey-js/src/autogen/entities.ts @@ -91,6 +91,8 @@ export type AdminQueueRemoveJobRequest = operations['admin___queue___remove-job' export type AdminQueueRetryJobRequest = operations['admin___queue___retry-job']['requestBody']['content']['application/json']; export type AdminQueueShowJobRequest = operations['admin___queue___show-job']['requestBody']['content']['application/json']; export type AdminQueueShowJobResponse = operations['admin___queue___show-job']['responses']['200']['content']['application/json']; +export type AdminQueueShowJobLogsRequest = operations['admin___queue___show-job-logs']['requestBody']['content']['application/json']; +export type AdminQueueShowJobLogsResponse = operations['admin___queue___show-job-logs']['responses']['200']['content']['application/json']; export type AdminQueueStatsResponse = operations['admin___queue___stats']['responses']['200']['content']['application/json']; export type AdminRelaysAddRequest = operations['admin___relays___add']['requestBody']['content']['application/json']; export type AdminRelaysAddResponse = operations['admin___relays___add']['responses']['200']['content']['application/json']; diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts index c0a6dca67e..50a96174c7 100644 --- a/packages/misskey-js/src/autogen/types.ts +++ b/packages/misskey-js/src/autogen/types.ts @@ -584,6 +584,15 @@ export type paths = { */ post: operations['admin___queue___show-job']; }; + '/admin/queue/show-job-logs': { + /** + * admin/queue/show-job-logs + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:queue* + */ + post: operations['admin___queue___show-job-logs']; + }; '/admin/queue/stats': { /** * admin/queue/stats @@ -10167,6 +10176,73 @@ export interface operations { }; }; }; + 'admin___queue___show-job-logs': { + requestBody: { + content: { + 'application/json': { + /** @enum {string} */ + queue: 'system' | 'endedPollNotification' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver'; + jobId: string; + }; + }; + }; + responses: { + /** @description OK (with results) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': string[]; + }; + }; + /** @description Client error */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Authentication error */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Forbidden error */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description I'm Ai */ + 418: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + }; + }; admin___queue___stats: { responses: { /** @description OK (with results) */