From 69fc71de7b71c5c42117f5cd5c7f2a196e6bfda1 Mon Sep 17 00:00:00 2001 From: Andrey Zhavoronkov Date: Tue, 31 Jan 2023 08:59:41 +0200 Subject: [PATCH 01/71] added initail version of clickhouse based analytics --- components/analytics/clickhouse/init.sh | 47 ++++ components/analytics/grafana/Dockerfile | 13 + .../grafana/dashboards/cvat-logs.json | 237 ++++++++++++++++++ components/analytics/kibana_conf.yml | 10 +- components/analytics/vector/vector.toml | 29 +++ cvat-core/src/enums.ts | 61 +++-- cvat-core/src/log.ts | 78 +++--- cvat-core/src/logger-storage.ts | 34 +-- cvat-core/src/session-implementation.ts | 21 +- .../global-error-boundary.tsx | 4 +- cvat-ui/src/components/header/header.tsx | 4 +- cvat-ui/src/index.tsx | 4 +- cvat/apps/__init__.py | 0 cvat/apps/engine/log.py | 5 + cvat/apps/engine/mixins.py | 4 + cvat/apps/engine/serializers.py | 30 --- cvat/apps/engine/task.py | 2 + cvat/apps/engine/tests/test_rest_api.py | 2 +- cvat/apps/engine/views.py | 60 +---- cvat/apps/log_viewer/apps.py | 4 + cvat/apps/log_viewer/urls.py | 2 +- cvat/apps/log_viewer/views.py | 6 +- cvat/apps/logs/apps.py | 12 + cvat/apps/logs/event.py | 71 ++++++ cvat/apps/logs/formatter.py | 10 + cvat/apps/logs/log_exporter.py | 142 +++++++++++ cvat/apps/logs/serializers.py | 66 +++++ cvat/apps/logs/signals.py | 214 ++++++++++++++++ cvat/apps/logs/urls.py | 13 + cvat/apps/logs/views.py | 140 +++++++++++ cvat/requirements/base.txt | 1 + cvat/settings/base.py | 34 ++- cvat/settings/development.py | 2 +- cvat/urls.py | 3 + docker-compose.dev.yml | 12 + docker-compose.yml | 94 +++++++ tests/python/rest_api/test_analytics.py | 2 +- 37 files changed, 1249 insertions(+), 224 deletions(-) create mode 100755 components/analytics/clickhouse/init.sh create mode 100644 components/analytics/grafana/Dockerfile create mode 100644 components/analytics/grafana/dashboards/cvat-logs.json create mode 100644 components/analytics/vector/vector.toml create mode 100644 cvat/apps/__init__.py create mode 100644 cvat/apps/logs/apps.py create mode 100644 cvat/apps/logs/event.py create mode 100644 cvat/apps/logs/formatter.py create mode 100644 cvat/apps/logs/log_exporter.py create mode 100644 cvat/apps/logs/serializers.py create mode 100644 cvat/apps/logs/signals.py create mode 100644 cvat/apps/logs/urls.py create mode 100644 cvat/apps/logs/views.py diff --git a/components/analytics/clickhouse/init.sh b/components/analytics/clickhouse/init.sh new file mode 100755 index 00000000000..903cc1cd3cf --- /dev/null +++ b/components/analytics/clickhouse/init.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +CLICKHOUSE_DB="${CLICKHOUSE_DB:-cvat}"; +CLICKHOUSE_USER="${CLICKHOUSE_USER:-user}"; +CLICKHOUSE_PASSWORD="${CLICKHOUSE_PASSWORD:-password}"; + +cat < /etc/clickhouse-server/users.d/user.xml + + + + <${CLICKHOUSE_USER}> + default + + ::/0 + + ${CLICKHOUSE_PASSWORD} + default + + + +EOT + +clickhouse-client --query "CREATE DATABASE IF NOT EXISTS ${CLICKHOUSE_DB}"; + +echo " +CREATE TABLE IF NOT EXISTS ${CLICKHOUSE_DB}.logs +( + \`scope\` String NOT NULL, + \`obj_name\` String NULL, + \`obj_id\` UInt64 NULL, + \`obj_val\` String NULL, + \`source\` String NOT NULL, + \`timestamp\` DateTime64(3, 'Etc/UTC') NOT NULL, + \`count\` UInt16 NULL, + \`duration\` UInt32 DEFAULT toUInt32(0), + \`project\` UInt64 NULL, + \`task\` UInt64 NULL, + \`job\` UInt64 NULL, + \`user\` UInt64 NULL, + \`organization\` UInt64 NULL, + \`payload\` String NULL +) +ENGINE = MergeTree +PARTITION BY toYYYYMM(timestamp) +ORDER BY (timestamp) +SETTINGS index_granularity = 8192 +;" | clickhouse-client diff --git a/components/analytics/grafana/Dockerfile b/components/analytics/grafana/Dockerfile new file mode 100644 index 00000000000..d5e99d4ad15 --- /dev/null +++ b/components/analytics/grafana/Dockerfile @@ -0,0 +1,13 @@ +FROM grafana/grafana:9.3.6-ubuntu + +ARG CLICKHOUSE_DATASOURCE_VERSION=2.0.7 + +WORKDIR /tmp +USER root + +RUN curl -vkL https://github.com/grafana/clickhouse-datasource/releases/download/v${CLICKHOUSE_DATASOURCE_VERSION}/grafana-clickhouse-datasource-${CLICKHOUSE_DATASOURCE_VERSION}.linux_amd64.zip -o grafana-clickhouse-datasource-${CLICKHOUSE_DATASOURCE_VERSION}.linux_amd64.zip + +RUN apt-get update && apt-get install -y unzip && \ + unzip grafana-clickhouse-datasource-${CLICKHOUSE_DATASOURCE_VERSION}.linux_amd64.zip -d /var/lib/grafana/plugins/ + +COPY dashboards/cvat-logs.json /var/lib/grafana/dashboards/ diff --git a/components/analytics/grafana/dashboards/cvat-logs.json b/components/analytics/grafana/dashboards/cvat-logs.json new file mode 100644 index 00000000000..a36c02ef245 --- /dev/null +++ b/components/analytics/grafana/dashboards/cvat-logs.json @@ -0,0 +1,237 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 2, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "grafana-clickhouse-datasource", + "uid": "PDEE91DDB90597936" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "auto", + "filterable": false, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 13, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 2, + "options": { + "footer": { + "enablePagination": true, + "fields": [ + "Working time(h)", + "Activity" + ], + "reducer": [ + "sum" + ], + "show": true + }, + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "9.3.6", + "targets": [ + { + "datasource": { + "type": "grafana-clickhouse-datasource", + "uid": "PDEE91DDB90597936" + }, + "format": 1, + "meta": { + "builderOptions": { + "fields": [], + "limit": 100, + "mode": "list" + } + }, + "queryType": "sql", + "rawSql": "SELECT\r\n user as User,\r\n project as Project,\r\n task as Task,\r\n job as Job, sum(JSONExtractUInt(payload, 'working_time')) / 1000 / 3600 as \"Working time(h)\",\r\n count() as Activity\r\nFROM cvat.logs\r\nWHERE JSONHas(payload, 'working_time')\r\n AND $__timeFilter(timestamp)\r\n AND user IN (${users})\r\n AND (-1 IN (${projects}) OR project IN (${projects}))\r\n AND task IN (${tasks})\r\n AND job IN (${jobs})\r\n AND source = 'client'\r\nGROUP BY user, project, task, job", + "refId": "A" + } + ], + "title": "Working time", + "type": "table" + } + ], + "schemaVersion": 37, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": { + "type": "grafana-clickhouse-datasource", + "uid": "PDEE91DDB90597936" + }, + "definition": "SELECT user\nFROM cvat.logs\nWHERE $__timeFilter(timestamp)\n AND source = 'client'", + "hide": 0, + "includeAll": true, + "label": "User", + "multi": true, + "name": "users", + "options": [], + "query": "SELECT user\nFROM cvat.logs\nWHERE $__timeFilter(timestamp)\n AND source = 'client'", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "type": "query" + }, + { + "allValue": "-1", + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": { + "type": "grafana-clickhouse-datasource", + "uid": "PDEE91DDB90597936" + }, + "definition": "SELECT project\nFROM cvat.logs\nWHERE $__timeFilter(timestamp)\n AND project IS NOT NULL\n AND source = 'client'", + "hide": 0, + "includeAll": true, + "label": "Project", + "multi": true, + "name": "projects", + "options": [], + "query": "SELECT project\nFROM cvat.logs\nWHERE $__timeFilter(timestamp)\n AND project IS NOT NULL\n AND source = 'client'", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "type": "query" + }, + { + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "grafana-clickhouse-datasource", + "uid": "PDEE91DDB90597936" + }, + "definition": "SELECT task\nFROM cvat.logs\nWHERE $__timeFilter(timestamp) \n AND task IS NOT NULL\n AND source = 'client'\n AND (-1 IN (${projects}) OR project IN (${projects}))", + "description": "", + "hide": 0, + "includeAll": true, + "label": "Task", + "multi": true, + "name": "tasks", + "options": [], + "query": "SELECT task\nFROM cvat.logs\nWHERE $__timeFilter(timestamp) \n AND task IS NOT NULL\n AND source = 'client'\n AND (-1 IN (${projects}) OR project IN (${projects}))", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "type": "query" + }, + { + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": { + "type": "grafana-clickhouse-datasource", + "uid": "PDEE91DDB90597936" + }, + "definition": "SELECT job\nFROM cvat.logs\nWHERE $__timeFilter(timestamp)\n AND job IS NOT NULL\n AND source = 'client'\n AND task in (${tasks})", + "hide": 0, + "includeAll": true, + "label": "Job", + "multi": true, + "name": "jobs", + "options": [], + "query": "SELECT job\nFROM cvat.logs\nWHERE $__timeFilter(timestamp)\n AND job IS NOT NULL\n AND source = 'client'\n AND task in (${tasks})", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-3h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "CVAT Statistics", + "uid": "w0if6WAVz", + "version": 26, + "weekStart": "" +} \ No newline at end of file diff --git a/components/analytics/kibana_conf.yml b/components/analytics/kibana_conf.yml index e5ccc75b323..f36a300379d 100644 --- a/components/analytics/kibana_conf.yml +++ b/components/analytics/kibana_conf.yml @@ -1,20 +1,20 @@ http: routers: - kibana: + grafana: entryPoints: - web middlewares: - analytics-auth - strip-prefix - service: kibana + service: grafana rule: Host(`{{ env "CVAT_HOST" }}`) && PathPrefix(`/analytics`) - kibana_https: + grafana_https: entryPoints: - websecure middlewares: - analytics-auth - strip-prefix - service: kibana + service: grafana tls: {} rule: Host(`{{ env "CVAT_HOST" }}`) && PathPrefix(`/analytics`) @@ -32,7 +32,7 @@ http: - /analytics services: - kibana: + grafana: loadBalancer: servers: - url: http://{{ env "DJANGO_LOG_VIEWER_HOST" }}:{{ env "DJANGO_LOG_VIEWER_PORT" }} diff --git a/components/analytics/vector/vector.toml b/components/analytics/vector/vector.toml new file mode 100644 index 00000000000..a4cd98d85fe --- /dev/null +++ b/components/analytics/vector/vector.toml @@ -0,0 +1,29 @@ +[sources.http-logs] +type = "http_server" +address = "0.0.0.0:80" +encoding = "json" + +[sinks.console] +type = "console" +inputs = [ "http-logs" ] +target = "stdout" + + [sinks.console.encoding] + codec = "json" + + + + + +[sinks.clickhouse] +inputs = [ "http-logs" ] +type = "clickhouse" +database = "${CLICKHOUSE_DB}" +table = "logs" +auth.strategy = "basic" +auth.user = "${CLICKHOUSE_USER}" +auth.password = "${CLICKHOUSE_PASSWORD}" +endpoint = "http://clickhouse:8123" +batch.timeout_secs = 10 +request.concurrency = "adaptive" +encoding.only_fields = ["scope", "obj_name", "obj_id", "obj_val", "source", "timestamp", "count", "duration", "project", "task", "job", "user", "organization", "payload"] diff --git a/cvat-core/src/enums.ts b/cvat-core/src/enums.ts index 1990dc1a115..6b4df016097 100644 --- a/cvat-core/src/enums.ts +++ b/cvat-core/src/enums.ts @@ -76,37 +76,36 @@ export enum Source { } export enum LogType { - loadJob = 'Load job', - saveJob = 'Save job', - restoreJob = 'Restore job', - uploadAnnotations = 'Upload annotations', - sendUserActivity = 'Send user activity', - sendException = 'Send exception', - sendTaskInfo = 'Send task info', - - drawObject = 'Draw object', - pasteObject = 'Paste object', - copyObject = 'Copy object', - propagateObject = 'Propagate object', - dragObject = 'Drag object', - resizeObject = 'Resize object', - deleteObject = 'Delete object', - lockObject = 'Lock object', - mergeObjects = 'Merge objects', - changeAttribute = 'Change attribute', - changeLabel = 'Change label', - - changeFrame = 'Change frame', - moveImage = 'Move image', - zoomImage = 'Zoom image', - fitImage = 'Fit image', - rotateImage = 'Rotate image', - - undoAction = 'Undo action', - redoAction = 'Redo action', - - pressShortcut = 'Press shortcut', - debugInfo = 'Debug info', + loadJob = 'load:job', + saveJob = 'save:job', + restoreJob = 'restore:job', + uploadAnnotations = 'upload:annotations', + exception = 'send:exception', + sendTaskInfo = 'send:task_info', + + drawObject = 'add:object', + pasteObject = 'paste:object', + copyObject = 'copy:object', + propagateObject = 'propagate:object', + dragObject = 'drag:object', + resizeObject = 'resize:object', + deleteObject = 'delete:object', + lockObject = 'lock:object', + mergeObjects = 'merge:objects', + changeAttribute = 'change:attribute', + changeLabel = 'change:label', + + changeFrame = 'change:frame', + moveImage = 'move:image', + zoomImage = 'zoom:image', + fitImage = 'fit:image', + rotateImage = 'rotate:image', + + undoAction = 'action:undo', + redoAction = 'action:redo', + + pressShortcut = 'press:shortcut', + debugInfo = 'send:debug_info', } export enum HistoryActions { diff --git a/cvat-core/src/log.ts b/cvat-core/src/log.ts index 40d7aea585f..d209528fbd8 100644 --- a/cvat-core/src/log.ts +++ b/cvat-core/src/log.ts @@ -10,7 +10,7 @@ import { ArgumentError } from './exceptions'; export class Log { public readonly id: number; - public readonly type: LogType; + public readonly scope: LogType; public readonly time: Date; public payload: any; @@ -20,7 +20,7 @@ export class Log { constructor(logType: LogType, payload: any) { this.onCloseCallback = null; - this.type = logType; + this.scope = logType; this.payload = { ...payload }; this.time = new Date(); } @@ -45,11 +45,22 @@ export class Log { public dump(): any { const payload = { ...this.payload }; const body = { - name: this.type, - time: this.time.toISOString(), + scope: this.scope, + timestamp: this.time.toISOString(), }; - for (const field of ['client_id', 'job_id', 'task_id', 'is_active']) { + for (const field of [ + 'obj_name', + 'obj_id', + 'obj_val', + 'count', + 'duration', + 'project', + 'task', + 'job', + 'user', + 'organization', + ]) { if (field in payload) { body[field] = payload[field]; delete payload[field]; @@ -58,7 +69,7 @@ export class Log { return { ...body, - payload, + payload: JSON.stringify(payload), }; } @@ -90,7 +101,7 @@ class LogWithCount extends Log { public validatePayload(): void { super.validatePayload.call(this); if (!Number.isInteger(this.payload.count) || this.payload.count < 1) { - const message = `The field "count" is required for "${this.type}" log. It must be a positive integer`; + const message = `The field "count" is required for "${this.scope}" log. It must be a positive integer`; throw new ArgumentError(message); } } @@ -99,7 +110,7 @@ class LogWithCount extends Log { class LogWithObjectsInfo extends Log { public validatePayload(): void { const generateError = (name: string, range: string): void => { - const message = `The field "${name}" is required for "${this.type}" log. ${range}`; + const message = `The field "${name}" is required for "${this.scope}" log. ${range}`; throw new ArgumentError(message); }; @@ -137,75 +148,46 @@ class LogWithObjectsInfo extends Log { } } -class LogWithWorkingTime extends Log { - public validatePayload(): void { - super.validatePayload.call(this); - - if ( - !('working_time' in this.payload) || - !(typeof this.payload.working_time === 'number') || - this.payload.working_time < 0 - ) { - const message = ` - The field "working_time" is required for ${this.type} log. It must be a number not less than 0 - `; - throw new ArgumentError(message); - } - } -} - class LogWithExceptionInfo extends Log { public validatePayload(): void { super.validatePayload.call(this); if (typeof this.payload.message !== 'string') { - const message = `The field "message" is required for ${this.type} log. It must be a string`; + const message = `The field "message" is required for ${this.scope} log. It must be a string`; throw new ArgumentError(message); } if (typeof this.payload.filename !== 'string') { - const message = `The field "filename" is required for ${this.type} log. It must be a string`; + const message = `The field "filename" is required for ${this.scope} log. It must be a string`; throw new ArgumentError(message); } if (typeof this.payload.line !== 'number') { - const message = `The field "line" is required for ${this.type} log. It must be a number`; + const message = `The field "line" is required for ${this.scope} log. It must be a number`; throw new ArgumentError(message); } if (typeof this.payload.column !== 'number') { - const message = `The field "column" is required for ${this.type} log. It must be a number`; + const message = `The field "column" is required for ${this.scope} log. It must be a number`; throw new ArgumentError(message); } if (typeof this.payload.stack !== 'string') { - const message = `The field "stack" is required for ${this.type} log. It must be a string`; + const message = `The field "stack" is required for ${this.scope} log. It must be a string`; throw new ArgumentError(message); } } public dump(): any { - let body = super.dump(); - const { payload } = body; + const body = super.dump(); const client = detect(); - body = { - ...body, - message: payload.message, - filename: payload.filename, - line: payload.line, - column: payload.column, - stack: payload.stack, + body.payload = { + ...body.payload, system: client.os, client: client.name, version: client.version, }; - delete payload.message; - delete payload.filename; - delete payload.line; - delete payload.column; - delete payload.stack; - return body; } } @@ -226,11 +208,7 @@ export default function logFactory(logType: LogType, payload: any): Log { return new LogWithObjectsInfo(logType, payload); } - if (logType === LogType.sendUserActivity) { - return new LogWithWorkingTime(logType, payload); - } - - if (logType === LogType.sendException) { + if (logType === LogType.exception) { return new LogWithExceptionInfo(logType, payload); } diff --git a/cvat-core/src/logger-storage.ts b/cvat-core/src/logger-storage.ts index c9a5593a94e..01ca037a21b 100644 --- a/cvat-core/src/logger-storage.ts +++ b/cvat-core/src/logger-storage.ts @@ -9,8 +9,6 @@ import logFactory, { Log } from './log'; import { LogType } from './enums'; import { ArgumentError } from './exceptions'; -const WORKING_TIME_THRESHOLD = 100000; // ms, 1.66 min - function sleep(ms): Promise { return new Promise((resolve) => { setTimeout(resolve, ms); @@ -25,8 +23,6 @@ interface IgnoreRule { class LoggerStorage { public clientID: string; - public lastLogTime: number; - public workingTime: number; public collection: Array; public ignoreRules: Record; public isActiveChecker: (() => boolean) | null; @@ -34,8 +30,6 @@ class LoggerStorage { constructor() { this.clientID = Date.now().toString().substr(-6); - this.lastLogTime = Date.now(); - this.workingTime = 0; this.collection = []; this.isActiveChecker = null; this.saving = false; @@ -59,15 +53,6 @@ class LoggerStorage { }; } - protected updateWorkingTime(): void { - if (!this.isActiveChecker || this.isActiveChecker()) { - const lastLogTime = Date.now(); - const diff = lastLogTime - this.lastLogTime; - this.workingTime += diff < WORKING_TIME_THRESHOLD ? diff : 0; - this.lastLogTime = lastLogTime; - } - } - public async configure(isActiveChecker, activityHelper): Promise { const result = await PluginRegistry.apiWrapper.call( this, @@ -103,7 +88,6 @@ Object.defineProperties(LoggerStorage.prototype.configure, { } this.isActiveChecker = () => !!isActiveChecker(); - userActivityCallback.push(this.updateWorkingTime.bind(this)); }, }, }); @@ -130,7 +114,6 @@ Object.defineProperties(LoggerStorage.prototype.log, { ...payload, }; - this.updateWorkingTime(); return ignoreRule.lastLog; } } @@ -147,13 +130,12 @@ Object.defineProperties(LoggerStorage.prototype.log, { } const pushEvent = (): void => { - this.updateWorkingTime(); log.validatePayload(); log.onClose(null); this.collection.push(log); }; - if (log.type === LogType.sendException) { + if (log.scope === LogType.exception) { serverProxy.server.exception(log.dump()).catch(() => { pushEvent(); }); @@ -186,30 +168,28 @@ Object.defineProperties(LoggerStorage.prototype.save, { const logPayload: any = { client_id: this.clientID, - working_time: this.workingTime, }; if (this.isActiveChecker) { logPayload.is_active = this.isActiveChecker(); } - if (lastLog && lastLog.type === LogType.sendTaskInfo) { + if (lastLog && lastLog.scope === LogType.sendTaskInfo) { logPayload.job_id = lastLog.payload.job_id; logPayload.task_id = lastLog.payload.task_id; } - const userActivityLog = logFactory(LogType.sendUserActivity, logPayload); - collectionToSend.push(userActivityLog); - try { this.saving = true; - await serverProxy.logs.save(collectionToSend.map((log) => log.dump())); + const sendTimestamp = new Date(); + await serverProxy.logs.save({ + events: collectionToSend.map((log) => log.dump()), + send_timestamp: sendTimestamp.toISOString(), + }); for (const rule of Object.values(this.ignoreRules)) { rule.lastLog = null; } this.collection = []; - this.workingTime = 0; - this.lastLogTime = Date.now(); } finally { this.saving = false; } diff --git a/cvat-core/src/session-implementation.ts b/cvat-core/src/session-implementation.ts index 578f7cf7da2..e9eb659e2e1 100644 --- a/cvat-core/src/session-implementation.ts +++ b/cvat-core/src/session-implementation.ts @@ -343,7 +343,16 @@ export function implementJob(Job) { }; Job.prototype.logger.log.implementation = async function (logType, payload, wait) { - const result = await loggerStorage.log(logType, { ...payload, task_id: this.taskId, job_id: this.id }, wait); + const result = await loggerStorage.log( + logType, + { + ...payload, + project: this.projectId, + task: this.taskId, + job: this.id, + }, + wait, + ); return result; }; @@ -785,7 +794,15 @@ export function implementTask(Task) { }; Task.prototype.logger.log.implementation = async function (logType, payload, wait) { - const result = await loggerStorage.log(logType, { ...payload, task_id: this.id }, wait); + const result = await loggerStorage.log( + logType, + { + ...payload, + project: this.projectId, + task: this.id, + }, + wait, + ); return result; }; diff --git a/cvat-ui/src/components/global-error-boundary/global-error-boundary.tsx b/cvat-ui/src/components/global-error-boundary/global-error-boundary.tsx index a5e4443ad1f..26ae975643c 100644 --- a/cvat-ui/src/components/global-error-boundary/global-error-boundary.tsx +++ b/cvat-ui/src/components/global-error-boundary/global-error-boundary.tsx @@ -97,9 +97,9 @@ class GlobalErrorBoundary extends React.PureComponent { }; if (job) { - job.logger.log(LogType.sendException, logPayload); + job.logger.log(LogType.exception, logPayload); } else { - logger.log(LogType.sendException, logPayload); + logger.log(LogType.exception, logPayload); } } diff --git a/cvat-ui/src/components/header/header.tsx b/cvat-ui/src/components/header/header.tsx index 0a187749fb1..e311ec6ce12 100644 --- a/cvat-ui/src/components/header/header.tsx +++ b/cvat-ui/src/components/header/header.tsx @@ -449,12 +449,12 @@ function HeaderContainer(props: Props): JSX.Element {