mirror of
https://github.com/versia-pub/server.git
synced 2025-12-06 08:28:19 +01:00
refactor: ♻️ Rewrite logging logic into a unified package
This commit is contained in:
parent
e1bd389bf1
commit
aff51b651c
25
.github/config.workflow.toml
vendored
25
.github/config.workflow.toml
vendored
|
|
@ -429,31 +429,28 @@ text = "No spam"
|
||||||
|
|
||||||
[logging]
|
[logging]
|
||||||
|
|
||||||
# Available levels: debug, info, warning, error, fatal
|
# Available levels: trace, debug, info, warning, error, fatal
|
||||||
log_level = "debug"
|
log_level = "info" # For console output
|
||||||
|
|
||||||
log_file_path = "logs/versia.log"
|
|
||||||
|
|
||||||
[logging.types]
|
|
||||||
# Either pass a boolean
|
|
||||||
# requests = true
|
|
||||||
# Or a table with the following keys:
|
|
||||||
# requests_content = { level = "debug", log_file_path = "logs/requests.log" }
|
|
||||||
# Available types are: requests, responses, requests_content, filters
|
|
||||||
|
|
||||||
|
# [logging.file]
|
||||||
|
# path = "logs/versia.log"
|
||||||
|
# log_level = "info"
|
||||||
|
#
|
||||||
|
# [logging.file.rotation]
|
||||||
|
# max_size = 10_000_000 # 10 MB
|
||||||
|
# max_files = 10 # Keep 10 rotated files
|
||||||
|
#
|
||||||
# https://sentry.io support
|
# https://sentry.io support
|
||||||
# Uncomment to enable
|
|
||||||
# [logging.sentry]
|
# [logging.sentry]
|
||||||
# Sentry DSN for error logging
|
|
||||||
# dsn = "https://example.com"
|
# dsn = "https://example.com"
|
||||||
# debug = false
|
# debug = false
|
||||||
|
|
||||||
# sample_rate = 1.0
|
# sample_rate = 1.0
|
||||||
# traces_sample_rate = 1.0
|
# traces_sample_rate = 1.0
|
||||||
# Can also be regex
|
# Can also be regex
|
||||||
# trace_propagation_targets = []
|
# trace_propagation_targets = []
|
||||||
# max_breadcrumbs = 100
|
# max_breadcrumbs = 100
|
||||||
# environment = "production"
|
# environment = "production"
|
||||||
|
# log_level = "info"
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
# Whether to automatically load all plugins in the plugins directory
|
# Whether to automatically load all plugins in the plugins directory
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,6 @@ import {
|
||||||
} from "@versia-server/tests";
|
} from "@versia-server/tests";
|
||||||
import { bench, run } from "mitata";
|
import { bench, run } from "mitata";
|
||||||
import type { z } from "zod";
|
import type { z } from "zod";
|
||||||
import { configureLoggers } from "@/loggers";
|
|
||||||
|
|
||||||
await configureLoggers(true);
|
|
||||||
|
|
||||||
const { users, tokens, deleteUsers } = await getTestUsers(5);
|
const { users, tokens, deleteUsers } = await getTestUsers(5);
|
||||||
await getTestStatuses(40, users[0]);
|
await getTestStatuses(40, users[0]);
|
||||||
|
|
|
||||||
91
bun.lock
91
bun.lock
|
|
@ -14,12 +14,11 @@
|
||||||
"@hackmd/markdown-it-task-lists": "catalog:",
|
"@hackmd/markdown-it-task-lists": "catalog:",
|
||||||
"@hono/zod-validator": "catalog:",
|
"@hono/zod-validator": "catalog:",
|
||||||
"@inquirer/confirm": "catalog:",
|
"@inquirer/confirm": "catalog:",
|
||||||
"@logtape/file": "catalog:",
|
|
||||||
"@logtape/logtape": "catalog:",
|
|
||||||
"@scalar/hono-api-reference": "catalog:",
|
"@scalar/hono-api-reference": "catalog:",
|
||||||
"@sentry/bun": "catalog:",
|
"@sentry/bun": "catalog:",
|
||||||
"@versia-server/config": "workspace:*",
|
"@versia-server/config": "workspace:*",
|
||||||
"@versia-server/kit": "workspace:*",
|
"@versia-server/kit": "workspace:*",
|
||||||
|
"@versia-server/logging": "workspace:*",
|
||||||
"@versia-server/tests": "workspace:*",
|
"@versia-server/tests": "workspace:*",
|
||||||
"@versia/client": "workspace:*",
|
"@versia/client": "workspace:*",
|
||||||
"@versia/sdk": "workspace:*",
|
"@versia/sdk": "workspace:*",
|
||||||
|
|
@ -91,10 +90,10 @@
|
||||||
"version": "0.9.0-alpha.0",
|
"version": "0.9.0-alpha.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hono/zod-validator": "catalog:",
|
"@hono/zod-validator": "catalog:",
|
||||||
"@logtape/logtape": "catalog:",
|
|
||||||
"@scalar/hono-api-reference": "catalog:",
|
"@scalar/hono-api-reference": "catalog:",
|
||||||
"@versia-server/config": "workspace:*",
|
"@versia-server/config": "workspace:*",
|
||||||
"@versia-server/kit": "workspace:*",
|
"@versia-server/kit": "workspace:*",
|
||||||
|
"@versia-server/logging": "workspace:*",
|
||||||
"@versia-server/tests": "workspace:*",
|
"@versia-server/tests": "workspace:*",
|
||||||
"@versia/client": "workspace:*",
|
"@versia/client": "workspace:*",
|
||||||
"@versia/sdk": "workspace:*",
|
"@versia/sdk": "workspace:*",
|
||||||
|
|
@ -145,14 +144,27 @@
|
||||||
"zod-validation-error": "catalog:",
|
"zod-validation-error": "catalog:",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"packages/logging": {
|
||||||
|
"name": "@versia-server/logging",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"dependencies": {
|
||||||
|
"@logtape/file": "catalog:",
|
||||||
|
"@logtape/logtape": "catalog:",
|
||||||
|
"@logtape/otel": "catalog:",
|
||||||
|
"@logtape/sentry": "catalog:",
|
||||||
|
"@sentry/bun": "catalog:",
|
||||||
|
"@versia-server/config": "workspace:*",
|
||||||
|
"chalk": "catalog:",
|
||||||
|
},
|
||||||
|
},
|
||||||
"packages/plugin-kit": {
|
"packages/plugin-kit": {
|
||||||
"name": "@versia-server/kit",
|
"name": "@versia-server/kit",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hackmd/markdown-it-task-lists": "catalog:",
|
"@hackmd/markdown-it-task-lists": "catalog:",
|
||||||
"@hono/zod-validator": "catalog:",
|
"@hono/zod-validator": "catalog:",
|
||||||
"@logtape/logtape": "catalog:",
|
|
||||||
"@versia-server/config": "workspace:*",
|
"@versia-server/config": "workspace:*",
|
||||||
|
"@versia-server/logging": "workspace:*",
|
||||||
"@versia/client": "workspace:*",
|
"@versia/client": "workspace:*",
|
||||||
"@versia/sdk": "workspace:*",
|
"@versia/sdk": "workspace:*",
|
||||||
"altcha-lib": "catalog:",
|
"altcha-lib": "catalog:",
|
||||||
|
|
@ -199,9 +211,9 @@
|
||||||
"name": "@versia-server/worker",
|
"name": "@versia-server/worker",
|
||||||
"version": "0.9.0-alpha.0",
|
"version": "0.9.0-alpha.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@logtape/logtape": "catalog:",
|
|
||||||
"@versia-server/config": "workspace:*",
|
"@versia-server/config": "workspace:*",
|
||||||
"@versia-server/kit": "workspace:*",
|
"@versia-server/kit": "workspace:*",
|
||||||
|
"@versia-server/logging": "workspace:*",
|
||||||
"chalk": "catalog:",
|
"chalk": "catalog:",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -211,6 +223,7 @@
|
||||||
"esbuild",
|
"esbuild",
|
||||||
"@biomejs/biome",
|
"@biomejs/biome",
|
||||||
"msgpackr-extract",
|
"msgpackr-extract",
|
||||||
|
"protobufjs",
|
||||||
],
|
],
|
||||||
"catalog": {
|
"catalog": {
|
||||||
"@biomejs/biome": "^2.0.4",
|
"@biomejs/biome": "^2.0.4",
|
||||||
|
|
@ -226,6 +239,8 @@
|
||||||
"@inquirer/confirm": "^5.1.12",
|
"@inquirer/confirm": "^5.1.12",
|
||||||
"@logtape/file": "^1.0.0",
|
"@logtape/file": "^1.0.0",
|
||||||
"@logtape/logtape": "^1.0.0",
|
"@logtape/logtape": "^1.0.0",
|
||||||
|
"@logtape/otel": "^1.0.0",
|
||||||
|
"@logtape/sentry": "^1.0.0",
|
||||||
"@scalar/hono-api-reference": "^0.9.6",
|
"@scalar/hono-api-reference": "^0.9.6",
|
||||||
"@sentry/bun": "^9.29.0",
|
"@sentry/bun": "^9.29.0",
|
||||||
"@types/bun": "^1.2.17",
|
"@types/bun": "^1.2.17",
|
||||||
|
|
@ -513,6 +528,10 @@
|
||||||
|
|
||||||
"@logtape/logtape": ["@logtape/logtape@1.0.0", "", {}, "sha512-GOOiaJcHSJQfFt+khrtoxfQ29klDiG8UxrgC+lPt7K6HhwEMQnB47j7V0GQ6F8bnS7JIZgYQmbXb+yGUF2pKhA=="],
|
"@logtape/logtape": ["@logtape/logtape@1.0.0", "", {}, "sha512-GOOiaJcHSJQfFt+khrtoxfQ29klDiG8UxrgC+lPt7K6HhwEMQnB47j7V0GQ6F8bnS7JIZgYQmbXb+yGUF2pKhA=="],
|
||||||
|
|
||||||
|
"@logtape/otel": ["@logtape/otel@1.0.0", "", { "dependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/api-logs": "^0.202.0", "@opentelemetry/exporter-logs-otlp-http": "^0.202.0", "@opentelemetry/otlp-exporter-base": "^0.202.0", "@opentelemetry/resources": "^2.0.1", "@opentelemetry/sdk-logs": "^0.202.0", "@opentelemetry/semantic-conventions": "^1.34.0" }, "peerDependencies": { "@logtape/logtape": "1.0.0" } }, "sha512-SMfmIFSsayszoYyOUyG7fq1FgFzdwnATzOCGRNq8JLUZ4vdO5fURqsYt4kG1LO7m2ioOsNwc0KkcVKY/s9kjiw=="],
|
||||||
|
|
||||||
|
"@logtape/sentry": ["@logtape/sentry@1.0.0", "", { "dependencies": { "@sentry/core": "^9.28.1" }, "peerDependencies": { "@logtape/logtape": "1.0.0" } }, "sha512-GMYe0MRnumtE09sDCGmCkvuCmcZfqco8CknG5TQYILaX7IHD/TFchCNtxCEeeZUWnmwaRzWAXDm3+YDA4NZcWQ=="],
|
||||||
|
|
||||||
"@msgpackr-extract/msgpackr-extract-darwin-arm64": ["@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw=="],
|
"@msgpackr-extract/msgpackr-extract-darwin-arm64": ["@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw=="],
|
||||||
|
|
||||||
"@msgpackr-extract/msgpackr-extract-darwin-x64": ["@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw=="],
|
"@msgpackr-extract/msgpackr-extract-darwin-x64": ["@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw=="],
|
||||||
|
|
@ -533,12 +552,14 @@
|
||||||
|
|
||||||
"@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
|
"@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
|
||||||
|
|
||||||
"@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.57.2", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-uIX52NnTM0iBh84MShlpouI7UKqkZ7MrUszTmaypHBu4r7NofznSnQRfJ+uUeDtQDj6w8eFGg5KBLDAwAPz1+A=="],
|
"@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.202.0", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-fTBjMqKCfotFWfLzaKyhjLvyEyq5vDKTTFfBmx21btv3gvy8Lq6N5Dh2OzqeuN4DjtpSvNT1uNVfg08eD2Rfxw=="],
|
||||||
|
|
||||||
"@opentelemetry/context-async-hooks": ["@opentelemetry/context-async-hooks@1.30.1", "", { "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-s5vvxXPVdjqS3kTLKMeBMvop9hbWkwzBpu+mUO2M7sZtlkyDJGwFe33wRKnbaYDo8ExRVBIIdwIGrqpxHuKttA=="],
|
"@opentelemetry/context-async-hooks": ["@opentelemetry/context-async-hooks@1.30.1", "", { "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-s5vvxXPVdjqS3kTLKMeBMvop9hbWkwzBpu+mUO2M7sZtlkyDJGwFe33wRKnbaYDo8ExRVBIIdwIGrqpxHuKttA=="],
|
||||||
|
|
||||||
"@opentelemetry/core": ["@opentelemetry/core@1.30.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "1.28.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-OOCM2C/QIURhJMuKaekP3TRBxBKxG/TWWA0TL2J6nXUtDnuCtccy49LUJF8xPFXMX+0LMcxFpCo8M9cGY1W6rQ=="],
|
"@opentelemetry/core": ["@opentelemetry/core@1.30.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "1.28.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-OOCM2C/QIURhJMuKaekP3TRBxBKxG/TWWA0TL2J6nXUtDnuCtccy49LUJF8xPFXMX+0LMcxFpCo8M9cGY1W6rQ=="],
|
||||||
|
|
||||||
|
"@opentelemetry/exporter-logs-otlp-http": ["@opentelemetry/exporter-logs-otlp-http@0.202.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.202.0", "@opentelemetry/core": "2.0.1", "@opentelemetry/otlp-exporter-base": "0.202.0", "@opentelemetry/otlp-transformer": "0.202.0", "@opentelemetry/sdk-logs": "0.202.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-mJWLkmoG+3r+SsYQC+sbWoy1rjowJhMhFvFULeIPTxSI+EZzKPya0+NZ3+vhhgx2UTybGQlye3FBtCH3o6Rejg=="],
|
||||||
|
|
||||||
"@opentelemetry/instrumentation": ["@opentelemetry/instrumentation@0.57.2", "", { "dependencies": { "@opentelemetry/api-logs": "0.57.2", "@types/shimmer": "^1.2.0", "import-in-the-middle": "^1.8.1", "require-in-the-middle": "^7.1.1", "semver": "^7.5.2", "shimmer": "^1.2.1" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-BdBGhQBh8IjZ2oIIX6F2/Q3LKm/FDDKi6ccYKcBTeilh6SNdNKveDOLk73BkSJjQLJk6qe4Yh+hHw1UPhCDdrg=="],
|
"@opentelemetry/instrumentation": ["@opentelemetry/instrumentation@0.57.2", "", { "dependencies": { "@opentelemetry/api-logs": "0.57.2", "@types/shimmer": "^1.2.0", "import-in-the-middle": "^1.8.1", "require-in-the-middle": "^7.1.1", "semver": "^7.5.2", "shimmer": "^1.2.1" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-BdBGhQBh8IjZ2oIIX6F2/Q3LKm/FDDKi6ccYKcBTeilh6SNdNKveDOLk73BkSJjQLJk6qe4Yh+hHw1UPhCDdrg=="],
|
||||||
|
|
||||||
"@opentelemetry/instrumentation-amqplib": ["@opentelemetry/instrumentation-amqplib@0.46.1", "", { "dependencies": { "@opentelemetry/core": "^1.8.0", "@opentelemetry/instrumentation": "^0.57.1", "@opentelemetry/semantic-conventions": "^1.27.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-AyXVnlCf/xV3K/rNumzKxZqsULyITJH6OVLiW6730JPRqWA7Zc9bvYoVNpN6iOpTU8CasH34SU/ksVJmObFibQ=="],
|
"@opentelemetry/instrumentation-amqplib": ["@opentelemetry/instrumentation-amqplib@0.46.1", "", { "dependencies": { "@opentelemetry/core": "^1.8.0", "@opentelemetry/instrumentation": "^0.57.1", "@opentelemetry/semantic-conventions": "^1.27.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-AyXVnlCf/xV3K/rNumzKxZqsULyITJH6OVLiW6730JPRqWA7Zc9bvYoVNpN6iOpTU8CasH34SU/ksVJmObFibQ=="],
|
||||||
|
|
@ -585,9 +606,17 @@
|
||||||
|
|
||||||
"@opentelemetry/instrumentation-undici": ["@opentelemetry/instrumentation-undici@0.10.1", "", { "dependencies": { "@opentelemetry/core": "^1.8.0", "@opentelemetry/instrumentation": "^0.57.1" }, "peerDependencies": { "@opentelemetry/api": "^1.7.0" } }, "sha512-rkOGikPEyRpMCmNu9AQuV5dtRlDmJp2dK5sw8roVshAGoB6hH/3QjDtRhdwd75SsJwgynWUNRUYe0wAkTo16tQ=="],
|
"@opentelemetry/instrumentation-undici": ["@opentelemetry/instrumentation-undici@0.10.1", "", { "dependencies": { "@opentelemetry/core": "^1.8.0", "@opentelemetry/instrumentation": "^0.57.1" }, "peerDependencies": { "@opentelemetry/api": "^1.7.0" } }, "sha512-rkOGikPEyRpMCmNu9AQuV5dtRlDmJp2dK5sw8roVshAGoB6hH/3QjDtRhdwd75SsJwgynWUNRUYe0wAkTo16tQ=="],
|
||||||
|
|
||||||
|
"@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.202.0", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/otlp-transformer": "0.202.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-nMEOzel+pUFYuBJg2znGmHJWbmvMbdX5/RhoKNKowguMbURhz0fwik5tUKplLcUtl8wKPL1y9zPnPxeBn65N0Q=="],
|
||||||
|
|
||||||
|
"@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.202.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.202.0", "@opentelemetry/core": "2.0.1", "@opentelemetry/resources": "2.0.1", "@opentelemetry/sdk-logs": "0.202.0", "@opentelemetry/sdk-metrics": "2.0.1", "@opentelemetry/sdk-trace-base": "2.0.1", "protobufjs": "^7.3.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-5XO77QFzs9WkexvJQL9ksxL8oVFb/dfi9NWQSq7Sv0Efr9x3N+nb1iklP1TeVgxqJ7m1xWiC/Uv3wupiQGevMw=="],
|
||||||
|
|
||||||
"@opentelemetry/redis-common": ["@opentelemetry/redis-common@0.36.2", "", {}, "sha512-faYX1N0gpLhej/6nyp6bgRjzAKXn5GOEMYY7YhciSfCoITAktLUtQ36d24QEWNA1/WA1y6qQunCe0OhHRkVl9g=="],
|
"@opentelemetry/redis-common": ["@opentelemetry/redis-common@0.36.2", "", {}, "sha512-faYX1N0gpLhej/6nyp6bgRjzAKXn5GOEMYY7YhciSfCoITAktLUtQ36d24QEWNA1/WA1y6qQunCe0OhHRkVl9g=="],
|
||||||
|
|
||||||
"@opentelemetry/resources": ["@opentelemetry/resources@1.30.1", "", { "dependencies": { "@opentelemetry/core": "1.30.1", "@opentelemetry/semantic-conventions": "1.28.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-5UxZqiAgLYGFjS4s9qm5mBVo433u+dSPUFWVWXmLAD4wB65oMCoXaJP1KJa9DIYYMeHu3z4BZcStG3LC593cWA=="],
|
"@opentelemetry/resources": ["@opentelemetry/resources@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw=="],
|
||||||
|
|
||||||
|
"@opentelemetry/sdk-logs": ["@opentelemetry/sdk-logs@0.202.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.202.0", "@opentelemetry/core": "2.0.1", "@opentelemetry/resources": "2.0.1" }, "peerDependencies": { "@opentelemetry/api": ">=1.4.0 <1.10.0" } }, "sha512-pv8QiQLQzk4X909YKm0lnW4hpuQg4zHwJ4XBd5bZiXcd9urvrJNoNVKnxGHPiDVX/GiLFvr5DMYsDBQbZCypRQ=="],
|
||||||
|
|
||||||
|
"@opentelemetry/sdk-metrics": ["@opentelemetry/sdk-metrics@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/resources": "2.0.1" }, "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <1.10.0" } }, "sha512-wf8OaJoSnujMAHWR3g+/hGvNcsC16rf9s1So4JlMiFaFHiE4HpIA3oUh+uWZQ7CNuK8gVW/pQSkgoa5HkkOl0g=="],
|
||||||
|
|
||||||
"@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@1.30.1", "", { "dependencies": { "@opentelemetry/core": "1.30.1", "@opentelemetry/resources": "1.30.1", "@opentelemetry/semantic-conventions": "1.28.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-jVPgBbH1gCy2Lb7X0AVQ8XAfgg0pJ4nvl8/IiQA6nxOsPvS+0zMJaFSs2ltXe0J6C8dqjcnpyqINDJmU30+uOg=="],
|
"@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@1.30.1", "", { "dependencies": { "@opentelemetry/core": "1.30.1", "@opentelemetry/resources": "1.30.1", "@opentelemetry/semantic-conventions": "1.28.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-jVPgBbH1gCy2Lb7X0AVQ8XAfgg0pJ4nvl8/IiQA6nxOsPvS+0zMJaFSs2ltXe0J6C8dqjcnpyqINDJmU30+uOg=="],
|
||||||
|
|
||||||
|
|
@ -605,6 +634,26 @@
|
||||||
|
|
||||||
"@prisma/instrumentation": ["@prisma/instrumentation@6.8.2", "", { "dependencies": { "@opentelemetry/instrumentation": "^0.52.0 || ^0.53.0 || ^0.54.0 || ^0.55.0 || ^0.56.0 || ^0.57.0" }, "peerDependencies": { "@opentelemetry/api": "^1.8" } }, "sha512-5NCTbZjw7a+WIZ/ey6G8SY+YKcyM2zBF0hOT1muvqC9TbVtTCr5Qv3RL/2iNDOzLUHEvo4I1uEfioyfuNOGK8Q=="],
|
"@prisma/instrumentation": ["@prisma/instrumentation@6.8.2", "", { "dependencies": { "@opentelemetry/instrumentation": "^0.52.0 || ^0.53.0 || ^0.54.0 || ^0.55.0 || ^0.56.0 || ^0.57.0" }, "peerDependencies": { "@opentelemetry/api": "^1.8" } }, "sha512-5NCTbZjw7a+WIZ/ey6G8SY+YKcyM2zBF0hOT1muvqC9TbVtTCr5Qv3RL/2iNDOzLUHEvo4I1uEfioyfuNOGK8Q=="],
|
||||||
|
|
||||||
|
"@protobufjs/aspromise": ["@protobufjs/aspromise@1.1.2", "", {}, "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="],
|
||||||
|
|
||||||
|
"@protobufjs/base64": ["@protobufjs/base64@1.1.2", "", {}, "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="],
|
||||||
|
|
||||||
|
"@protobufjs/codegen": ["@protobufjs/codegen@2.0.4", "", {}, "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="],
|
||||||
|
|
||||||
|
"@protobufjs/eventemitter": ["@protobufjs/eventemitter@1.1.0", "", {}, "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="],
|
||||||
|
|
||||||
|
"@protobufjs/fetch": ["@protobufjs/fetch@1.1.0", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" } }, "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ=="],
|
||||||
|
|
||||||
|
"@protobufjs/float": ["@protobufjs/float@1.0.2", "", {}, "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="],
|
||||||
|
|
||||||
|
"@protobufjs/inquire": ["@protobufjs/inquire@1.1.0", "", {}, "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="],
|
||||||
|
|
||||||
|
"@protobufjs/path": ["@protobufjs/path@1.1.2", "", {}, "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="],
|
||||||
|
|
||||||
|
"@protobufjs/pool": ["@protobufjs/pool@1.1.0", "", {}, "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="],
|
||||||
|
|
||||||
|
"@protobufjs/utf8": ["@protobufjs/utf8@1.1.0", "", {}, "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="],
|
||||||
|
|
||||||
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.44.0", "", { "os": "android", "cpu": "arm" }, "sha512-xEiEE5oDW6tK4jXCAyliuntGR+amEMO7HLtdSshVuhFnKTYoeYMyXQK7pLouAJJj5KHdwdn87bfHAR2nSdNAUA=="],
|
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.44.0", "", { "os": "android", "cpu": "arm" }, "sha512-xEiEE5oDW6tK4jXCAyliuntGR+amEMO7HLtdSshVuhFnKTYoeYMyXQK7pLouAJJj5KHdwdn87bfHAR2nSdNAUA=="],
|
||||||
|
|
||||||
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.44.0", "", { "os": "android", "cpu": "arm64" }, "sha512-uNSk/TgvMbskcHxXYHzqwiyBlJ/lGcv8DaUfcnNwict8ba9GTTNxfn3/FAoFZYgkaXXAdrAA+SLyKplyi349Jw=="],
|
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.44.0", "", { "os": "android", "cpu": "arm64" }, "sha512-uNSk/TgvMbskcHxXYHzqwiyBlJ/lGcv8DaUfcnNwict8ba9GTTNxfn3/FAoFZYgkaXXAdrAA+SLyKplyi349Jw=="],
|
||||||
|
|
@ -741,6 +790,8 @@
|
||||||
|
|
||||||
"@versia-server/kit": ["@versia-server/kit@workspace:packages/plugin-kit"],
|
"@versia-server/kit": ["@versia-server/kit@workspace:packages/plugin-kit"],
|
||||||
|
|
||||||
|
"@versia-server/logging": ["@versia-server/logging@workspace:packages/logging"],
|
||||||
|
|
||||||
"@versia-server/tests": ["@versia-server/tests@workspace:packages/tests"],
|
"@versia-server/tests": ["@versia-server/tests@workspace:packages/tests"],
|
||||||
|
|
||||||
"@versia-server/worker": ["@versia-server/worker@workspace:packages/worker"],
|
"@versia-server/worker": ["@versia-server/worker@workspace:packages/worker"],
|
||||||
|
|
@ -1125,6 +1176,8 @@
|
||||||
|
|
||||||
"log-symbols": ["log-symbols@6.0.0", "", { "dependencies": { "chalk": "^5.3.0", "is-unicode-supported": "^1.3.0" } }, "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw=="],
|
"log-symbols": ["log-symbols@6.0.0", "", { "dependencies": { "chalk": "^5.3.0", "is-unicode-supported": "^1.3.0" } }, "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw=="],
|
||||||
|
|
||||||
|
"long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="],
|
||||||
|
|
||||||
"lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
|
"lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
|
||||||
|
|
||||||
"luxon": ["luxon@3.6.1", "", {}, "sha512-tJLxrKJhO2ukZ5z0gyjY1zPh3Rh88Ej9P7jNrZiHMUXHae1yvI2imgOZtL1TO8TW6biMMKfTtAOoEJANgtWBMQ=="],
|
"luxon": ["luxon@3.6.1", "", {}, "sha512-tJLxrKJhO2ukZ5z0gyjY1zPh3Rh88Ej9P7jNrZiHMUXHae1yvI2imgOZtL1TO8TW6biMMKfTtAOoEJANgtWBMQ=="],
|
||||||
|
|
@ -1287,6 +1340,8 @@
|
||||||
|
|
||||||
"property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="],
|
"property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="],
|
||||||
|
|
||||||
|
"protobufjs": ["protobufjs@7.5.3", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, "sha512-sildjKwVqOI2kmFDiXQ6aEB0fjYTafpEvIBs8tOR8qI4spuL9OPROLVu2qZqi/xgCfsHIwVqlaF8JBjWFHnKbw=="],
|
||||||
|
|
||||||
"punycode.js": ["punycode.js@2.3.1", "", {}, "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA=="],
|
"punycode.js": ["punycode.js@2.3.1", "", {}, "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA=="],
|
||||||
|
|
||||||
"qs": ["qs@6.14.0", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w=="],
|
"qs": ["qs@6.14.0", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w=="],
|
||||||
|
|
@ -1525,9 +1580,25 @@
|
||||||
|
|
||||||
"@opentelemetry/core/@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.28.0", "", {}, "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA=="],
|
"@opentelemetry/core/@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.28.0", "", {}, "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA=="],
|
||||||
|
|
||||||
|
"@opentelemetry/exporter-logs-otlp-http/@opentelemetry/core": ["@opentelemetry/core@2.0.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw=="],
|
||||||
|
|
||||||
|
"@opentelemetry/instrumentation/@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.57.2", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-uIX52NnTM0iBh84MShlpouI7UKqkZ7MrUszTmaypHBu4r7NofznSnQRfJ+uUeDtQDj6w8eFGg5KBLDAwAPz1+A=="],
|
||||||
|
|
||||||
"@opentelemetry/instrumentation-http/@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.28.0", "", {}, "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA=="],
|
"@opentelemetry/instrumentation-http/@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.28.0", "", {}, "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA=="],
|
||||||
|
|
||||||
"@opentelemetry/resources/@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.28.0", "", {}, "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA=="],
|
"@opentelemetry/otlp-exporter-base/@opentelemetry/core": ["@opentelemetry/core@2.0.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw=="],
|
||||||
|
|
||||||
|
"@opentelemetry/otlp-transformer/@opentelemetry/core": ["@opentelemetry/core@2.0.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw=="],
|
||||||
|
|
||||||
|
"@opentelemetry/otlp-transformer/@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/resources": "2.0.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ=="],
|
||||||
|
|
||||||
|
"@opentelemetry/resources/@opentelemetry/core": ["@opentelemetry/core@2.0.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw=="],
|
||||||
|
|
||||||
|
"@opentelemetry/sdk-logs/@opentelemetry/core": ["@opentelemetry/core@2.0.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw=="],
|
||||||
|
|
||||||
|
"@opentelemetry/sdk-metrics/@opentelemetry/core": ["@opentelemetry/core@2.0.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw=="],
|
||||||
|
|
||||||
|
"@opentelemetry/sdk-trace-base/@opentelemetry/resources": ["@opentelemetry/resources@1.30.1", "", { "dependencies": { "@opentelemetry/core": "1.30.1", "@opentelemetry/semantic-conventions": "1.28.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-5UxZqiAgLYGFjS4s9qm5mBVo433u+dSPUFWVWXmLAD4wB65oMCoXaJP1KJa9DIYYMeHu3z4BZcStG3LC593cWA=="],
|
||||||
|
|
||||||
"@opentelemetry/sdk-trace-base/@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.28.0", "", {}, "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA=="],
|
"@opentelemetry/sdk-trace-base/@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.28.0", "", {}, "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA=="],
|
||||||
|
|
||||||
|
|
@ -1537,6 +1608,8 @@
|
||||||
|
|
||||||
"@scalar/types/zod": ["zod@3.24.1", "", {}, "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A=="],
|
"@scalar/types/zod": ["zod@3.24.1", "", {}, "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A=="],
|
||||||
|
|
||||||
|
"@sentry/node/@opentelemetry/resources": ["@opentelemetry/resources@1.30.1", "", { "dependencies": { "@opentelemetry/core": "1.30.1", "@opentelemetry/semantic-conventions": "1.28.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-5UxZqiAgLYGFjS4s9qm5mBVo433u+dSPUFWVWXmLAD4wB65oMCoXaJP1KJa9DIYYMeHu3z4BZcStG3LC593cWA=="],
|
||||||
|
|
||||||
"@ts-morph/common/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
|
"@ts-morph/common/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
|
||||||
|
|
||||||
"@vue/compiler-core/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
|
"@vue/compiler-core/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
|
||||||
|
|
@ -1649,6 +1722,8 @@
|
||||||
|
|
||||||
"@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="],
|
"@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="],
|
||||||
|
|
||||||
|
"@sentry/node/@opentelemetry/resources/@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.28.0", "", {}, "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA=="],
|
||||||
|
|
||||||
"@ts-morph/common/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
|
"@ts-morph/common/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
|
||||||
|
|
||||||
"cheerio-select/domutils/dom-serializer": ["dom-serializer@1.4.1", "", { "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", "entities": "^2.0.0" } }, "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag=="],
|
"cheerio-select/domutils/dom-serializer": ["dom-serializer@1.4.1", "", { "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", "entities": "^2.0.0" } }, "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag=="],
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import { getLogger, type Logger } from "@logtape/logtape";
|
|
||||||
import { EntitySorter, type JSONObject } from "@versia/sdk";
|
import { EntitySorter, type JSONObject } from "@versia/sdk";
|
||||||
import { verify } from "@versia/sdk/crypto";
|
import { verify } from "@versia/sdk/crypto";
|
||||||
import * as VersiaEntities from "@versia/sdk/entities";
|
import * as VersiaEntities from "@versia/sdk/entities";
|
||||||
|
|
@ -13,13 +12,13 @@ import {
|
||||||
User,
|
User,
|
||||||
} from "@versia-server/kit/db";
|
} from "@versia-server/kit/db";
|
||||||
import { Likes, Notes } from "@versia-server/kit/tables";
|
import { Likes, Notes } from "@versia-server/kit/tables";
|
||||||
|
import { federationInboxLogger } from "@versia-server/logging";
|
||||||
import type { SocketAddress } from "bun";
|
import type { SocketAddress } from "bun";
|
||||||
import { Glob } from "bun";
|
import { Glob } from "bun";
|
||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
import { and, eq } from "drizzle-orm";
|
import { and, eq } from "drizzle-orm";
|
||||||
import { matches } from "ip-matching";
|
import { matches } from "ip-matching";
|
||||||
import { isValidationError } from "zod-validation-error";
|
import { isValidationError } from "zod-validation-error";
|
||||||
import { sentry } from "@/sentry";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the hostname is defederated using glob matching.
|
* Checks if the hostname is defederated using glob matching.
|
||||||
|
|
@ -65,7 +64,6 @@ export class InboxProcessor {
|
||||||
key: CryptoKey;
|
key: CryptoKey;
|
||||||
} | null,
|
} | null,
|
||||||
private authorizationHeader?: string,
|
private authorizationHeader?: string,
|
||||||
private logger: Logger = getLogger(["federation", "inbox"]),
|
|
||||||
private requestIp: SocketAddress | null = null,
|
private requestIp: SocketAddress | null = null,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
|
@ -156,7 +154,7 @@ export class InboxProcessor {
|
||||||
*/
|
*/
|
||||||
public async process(): Promise<void> {
|
public async process(): Promise<void> {
|
||||||
!this.sender &&
|
!this.sender &&
|
||||||
this.logger.debug`Processing request from potential bridge`;
|
federationInboxLogger.debug`Processing request from potential bridge`;
|
||||||
|
|
||||||
if (this.sender && isDefederated(this.sender.instance.data.baseUrl)) {
|
if (this.sender && isDefederated(this.sender.instance.data.baseUrl)) {
|
||||||
// Return 201 to avoid
|
// Return 201 to avoid
|
||||||
|
|
@ -165,15 +163,15 @@ export class InboxProcessor {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.debug`Instance ${chalk.gray(
|
federationInboxLogger.debug`Instance ${chalk.gray(
|
||||||
this.sender?.instance.data.baseUrl,
|
this.sender?.instance.data.baseUrl,
|
||||||
)} is not defederated`;
|
)} is not defederated`;
|
||||||
|
|
||||||
const shouldCheckSignature = this.shouldCheckSignature();
|
const shouldCheckSignature = this.shouldCheckSignature();
|
||||||
|
|
||||||
shouldCheckSignature
|
shouldCheckSignature
|
||||||
? this.logger.debug`Checking signature`
|
? federationInboxLogger.debug`Checking signature`
|
||||||
: this.logger.debug`Skipping signature check`;
|
: federationInboxLogger.debug`Skipping signature check`;
|
||||||
|
|
||||||
if (shouldCheckSignature) {
|
if (shouldCheckSignature) {
|
||||||
const isValid = await this.isSignatureValid();
|
const isValid = await this.isSignatureValid();
|
||||||
|
|
@ -183,7 +181,7 @@ export class InboxProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldCheckSignature && this.logger.debug`Signature is valid`;
|
shouldCheckSignature && federationInboxLogger.debug`Signature is valid`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await new EntitySorter(this.body)
|
await new EntitySorter(this.body)
|
||||||
|
|
@ -596,8 +594,7 @@ export class InboxProcessor {
|
||||||
throw new ApiError(400, "Failed to process request", e.message);
|
throw new ApiError(400, "Failed to process request", e.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.error`${e}`;
|
federationInboxLogger.error`${e}`;
|
||||||
sentry?.captureException(e);
|
|
||||||
|
|
||||||
throw new ApiError(500, "Failed to process request", e.message);
|
throw new ApiError(500, "Failed to process request", e.message);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { readdir } from "node:fs/promises";
|
import { readdir } from "node:fs/promises";
|
||||||
import { getLogger, type Logger } from "@logtape/logtape";
|
|
||||||
import { config } from "@versia-server/config";
|
import { config } from "@versia-server/config";
|
||||||
import { type Manifest, manifestSchema, Plugin } from "@versia-server/kit";
|
import { type Manifest, manifestSchema, Plugin } from "@versia-server/kit";
|
||||||
|
import { pluginLogger, serverLogger } from "@versia-server/logging";
|
||||||
import { file, sleep } from "bun";
|
import { file, sleep } from "bun";
|
||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
import { parseJSON5, parseJSONC } from "confbox";
|
import { parseJSON5, parseJSONC } from "confbox";
|
||||||
|
|
@ -14,8 +14,6 @@ import type { HonoEnv } from "~/types/api";
|
||||||
* Class to manage plugins.
|
* Class to manage plugins.
|
||||||
*/
|
*/
|
||||||
export class PluginLoader {
|
export class PluginLoader {
|
||||||
private logger = getLogger("plugin");
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all directories in a given directory.
|
* Get all directories in a given directory.
|
||||||
* @param {string} dir - The directory to search.
|
* @param {string} dir - The directory to search.
|
||||||
|
|
@ -74,8 +72,7 @@ export class PluginLoader {
|
||||||
|
|
||||||
throw new Error(`Unsupported manifest file type: ${manifestFile}`);
|
throw new Error(`Unsupported manifest file type: ${manifestFile}`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logger
|
pluginLogger.fatal`Could not parse plugin manifest ${chalk.blue(manifestPath)} as ${manifestFile.split(".").pop()?.toUpperCase()}.`;
|
||||||
.fatal`Could not parse plugin manifest ${chalk.blue(manifestPath)} as ${manifestFile.split(".").pop()?.toUpperCase()}.`;
|
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -129,8 +126,7 @@ export class PluginLoader {
|
||||||
const result = await manifestSchema.safeParseAsync(manifest);
|
const result = await manifestSchema.safeParseAsync(manifest);
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
this.logger
|
pluginLogger.fatal`Plugin manifest ${chalk.blue(manifestPath)} is invalid.`;
|
||||||
.fatal`Plugin manifest ${chalk.blue(manifestPath)} is invalid.`;
|
|
||||||
throw fromZodError(result.error);
|
throw fromZodError(result.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -154,8 +150,7 @@ export class PluginLoader {
|
||||||
return plugin;
|
return plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger
|
pluginLogger.fatal`Default export of entrypoint ${chalk.blue(entrypoint)} at ${chalk.blue(dir)} is not a Plugin.`;
|
||||||
.fatal`Default export of entrypoint ${chalk.blue(entrypoint)} at ${chalk.blue(dir)} is not a Plugin.`;
|
|
||||||
|
|
||||||
throw new Error("Entrypoint is not a Plugin");
|
throw new Error("Entrypoint is not a Plugin");
|
||||||
}
|
}
|
||||||
|
|
@ -177,8 +172,7 @@ export class PluginLoader {
|
||||||
const disabledOn = (disabled?.length ?? 0) > 0;
|
const disabledOn = (disabled?.length ?? 0) > 0;
|
||||||
|
|
||||||
if (enabledOn && disabledOn) {
|
if (enabledOn && disabledOn) {
|
||||||
this.logger
|
pluginLogger.fatal`Both enabled and disabled lists are specified. Only one of them can be used.`;
|
||||||
.fatal`Both enabled and disabled lists are specified. Only one of them can be used.`;
|
|
||||||
throw new Error("Invalid configuration");
|
throw new Error("Invalid configuration");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -219,10 +213,9 @@ export class PluginLoader {
|
||||||
plugin: Plugin<ZodTypeAny>;
|
plugin: Plugin<ZodTypeAny>;
|
||||||
}[],
|
}[],
|
||||||
app: Hono<HonoEnv>,
|
app: Hono<HonoEnv>,
|
||||||
logger: Logger,
|
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
for (const data of plugins) {
|
for (const data of plugins) {
|
||||||
logger.info`Loading plugin ${chalk.blueBright(data.manifest.name)} ${chalk.blueBright(data.manifest.version)} ${chalk.gray(`[${plugins.indexOf(data) + 1}/${plugins.length}]`)}`;
|
serverLogger.info`Loading plugin ${chalk.blueBright(data.manifest.name)} ${chalk.blueBright(data.manifest.version)} ${chalk.gray(`[${plugins.indexOf(data) + 1}/${plugins.length}]`)}`;
|
||||||
|
|
||||||
const time1 = performance.now();
|
const time1 = performance.now();
|
||||||
|
|
||||||
|
|
@ -232,13 +225,13 @@ export class PluginLoader {
|
||||||
config.plugins?.config?.[data.manifest.name],
|
config.plugins?.config?.[data.manifest.name],
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.fatal`Error encountered while loading plugin ${chalk.blueBright(data.manifest.name)} ${chalk.blueBright(data.manifest.version)} configuration.`;
|
serverLogger.fatal`Error encountered while loading plugin ${chalk.blueBright(data.manifest.name)} ${chalk.blueBright(data.manifest.version)} configuration.`;
|
||||||
logger.fatal`This is due to invalid, missing or incomplete configuration.`;
|
serverLogger.fatal`This is due to invalid, missing or incomplete configuration.`;
|
||||||
logger.fatal`Put your configuration at ${chalk.blueBright(
|
serverLogger.fatal`Put your configuration at ${chalk.blueBright(
|
||||||
"plugins.config.<plugin-name>",
|
"plugins.config.<plugin-name>",
|
||||||
)}`;
|
)}`;
|
||||||
logger.fatal`Here is the error message, please fix the configuration file accordingly:`;
|
serverLogger.fatal`Here is the error message, please fix the configuration file accordingly:`;
|
||||||
logger.fatal`${(e as ValidationError).message}`;
|
serverLogger.fatal`${(e as ValidationError).message}`;
|
||||||
|
|
||||||
await sleep(Number.POSITIVE_INFINITY);
|
await sleep(Number.POSITIVE_INFINITY);
|
||||||
}
|
}
|
||||||
|
|
@ -250,7 +243,7 @@ export class PluginLoader {
|
||||||
|
|
||||||
const time3 = performance.now();
|
const time3 = performance.now();
|
||||||
|
|
||||||
logger.info`Plugin ${chalk.blueBright(data.manifest.name)} ${chalk.blueBright(
|
serverLogger.info`Plugin ${chalk.blueBright(data.manifest.name)} ${chalk.blueBright(
|
||||||
data.manifest.version,
|
data.manifest.version,
|
||||||
)} loaded in ${chalk.gray(
|
)} loaded in ${chalk.gray(
|
||||||
`${(time2 - time1).toFixed(2)}ms`,
|
`${(time2 - time1).toFixed(2)}ms`,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import { getLogger } from "@logtape/logtape";
|
|
||||||
import type { JSONObject } from "@versia/sdk";
|
import type { JSONObject } from "@versia/sdk";
|
||||||
import { config } from "@versia-server/config";
|
import { config } from "@versia-server/config";
|
||||||
import { ApiError } from "@versia-server/kit";
|
import { ApiError } from "@versia-server/kit";
|
||||||
|
|
@ -64,7 +63,6 @@ export const getInboxWorker = (): Worker<InboxJobData, void, InboxJobType> =>
|
||||||
data,
|
data,
|
||||||
null,
|
null,
|
||||||
headers.authorization,
|
headers.authorization,
|
||||||
getLogger(["federation", "inbox"]),
|
|
||||||
ip,
|
ip,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -160,7 +158,6 @@ export const getInboxWorker = (): Worker<InboxJobData, void, InboxJobType> =>
|
||||||
key,
|
key,
|
||||||
},
|
},
|
||||||
undefined,
|
undefined,
|
||||||
getLogger(["federation", "inbox"]),
|
|
||||||
ip,
|
ip,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,9 @@
|
||||||
* @description Sonic search integration for indexing and searching accounts and statuses
|
* @description Sonic search integration for indexing and searching accounts and statuses
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { getLogger } from "@logtape/logtape";
|
|
||||||
import { config } from "@versia-server/config";
|
import { config } from "@versia-server/config";
|
||||||
import { db, Note, User } from "@versia-server/kit/db";
|
import { db, Note, User } from "@versia-server/kit/db";
|
||||||
|
import { sonicLogger } from "@versia-server/logging";
|
||||||
import type { SQL, ValueOrArray } from "drizzle-orm";
|
import type { SQL, ValueOrArray } from "drizzle-orm";
|
||||||
import {
|
import {
|
||||||
Ingest as SonicChannelIngest,
|
Ingest as SonicChannelIngest,
|
||||||
|
|
@ -27,7 +27,6 @@ export class SonicSearchManager {
|
||||||
private searchChannel: SonicChannelSearch;
|
private searchChannel: SonicChannelSearch;
|
||||||
private ingestChannel: SonicChannelIngest;
|
private ingestChannel: SonicChannelIngest;
|
||||||
private connected = false;
|
private connected = false;
|
||||||
private logger = getLogger("sonic");
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param config Configuration for Sonic
|
* @param config Configuration for Sonic
|
||||||
|
|
@ -55,7 +54,7 @@ export class SonicSearchManager {
|
||||||
*/
|
*/
|
||||||
public async connect(silent = false): Promise<void> {
|
public async connect(silent = false): Promise<void> {
|
||||||
if (!config.search.enabled) {
|
if (!config.search.enabled) {
|
||||||
!silent && this.logger.info`Sonic search is disabled`;
|
!silent && sonicLogger.info`Sonic search is disabled`;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -63,28 +62,24 @@ export class SonicSearchManager {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
!silent && this.logger.info`Connecting to Sonic...`;
|
!silent && sonicLogger.info`Connecting to Sonic...`;
|
||||||
|
|
||||||
// Connect to Sonic
|
// Connect to Sonic
|
||||||
await new Promise<boolean>((resolve, reject) => {
|
await new Promise<boolean>((resolve, reject) => {
|
||||||
this.searchChannel.connect({
|
this.searchChannel.connect({
|
||||||
connected: (): void => {
|
connected: (): void => {
|
||||||
!silent &&
|
!silent &&
|
||||||
this.logger.info`Connected to Sonic Search Channel`;
|
sonicLogger.info`Connected to Sonic Search Channel`;
|
||||||
resolve(true);
|
resolve(true);
|
||||||
},
|
},
|
||||||
disconnected: (): void =>
|
disconnected: (): void =>
|
||||||
this.logger
|
sonicLogger.error`Disconnected from Sonic Search Channel. You might be using an incorrect password.`,
|
||||||
.error`Disconnected from Sonic Search Channel. You might be using an incorrect password.`,
|
|
||||||
timeout: (): void =>
|
timeout: (): void =>
|
||||||
this.logger
|
sonicLogger.error`Sonic Search Channel connection timed out`,
|
||||||
.error`Sonic Search Channel connection timed out`,
|
|
||||||
retrying: (): void =>
|
retrying: (): void =>
|
||||||
this.logger
|
sonicLogger.warn`Retrying connection to Sonic Search Channel`,
|
||||||
.warn`Retrying connection to Sonic Search Channel`,
|
|
||||||
error: (error): void => {
|
error: (error): void => {
|
||||||
this.logger
|
sonicLogger.error`Failed to connect to Sonic Search Channel: ${error}`;
|
||||||
.error`Failed to connect to Sonic Search Channel: ${error}`;
|
|
||||||
reject(error);
|
reject(error);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
@ -94,20 +89,17 @@ export class SonicSearchManager {
|
||||||
this.ingestChannel.connect({
|
this.ingestChannel.connect({
|
||||||
connected: (): void => {
|
connected: (): void => {
|
||||||
!silent &&
|
!silent &&
|
||||||
this.logger.info`Connected to Sonic Ingest Channel`;
|
sonicLogger.info`Connected to Sonic Ingest Channel`;
|
||||||
resolve(true);
|
resolve(true);
|
||||||
},
|
},
|
||||||
disconnected: (): void =>
|
disconnected: (): void =>
|
||||||
this.logger.error`Disconnected from Sonic Ingest Channel`,
|
sonicLogger.error`Disconnected from Sonic Ingest Channel`,
|
||||||
timeout: (): void =>
|
timeout: (): void =>
|
||||||
this.logger
|
sonicLogger.error`Sonic Ingest Channel connection timed out`,
|
||||||
.error`Sonic Ingest Channel connection timed out`,
|
|
||||||
retrying: (): void =>
|
retrying: (): void =>
|
||||||
this.logger
|
sonicLogger.warn`Retrying connection to Sonic Ingest Channel`,
|
||||||
.warn`Retrying connection to Sonic Ingest Channel`,
|
|
||||||
error: (error): void => {
|
error: (error): void => {
|
||||||
this.logger
|
sonicLogger.error`Failed to connect to Sonic Ingest Channel: ${error}`;
|
||||||
.error`Failed to connect to Sonic Ingest Channel: ${error}`;
|
|
||||||
reject(error);
|
reject(error);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
@ -119,9 +111,9 @@ export class SonicSearchManager {
|
||||||
this.ingestChannel.ping(),
|
this.ingestChannel.ping(),
|
||||||
]);
|
]);
|
||||||
this.connected = true;
|
this.connected = true;
|
||||||
!silent && this.logger.info`Connected to Sonic`;
|
!silent && sonicLogger.info`Connected to Sonic`;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger.fatal`Error while connecting to Sonic: ${error}`;
|
sonicLogger.fatal`Error while connecting to Sonic: ${error}`;
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -143,7 +135,7 @@ export class SonicSearchManager {
|
||||||
`${user.data.username} ${user.data.displayName} ${user.data.note}`,
|
`${user.data.username} ${user.data.displayName} ${user.data.note}`,
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger.error`Failed to add user to Sonic: ${error}`;
|
sonicLogger.error`Failed to add user to Sonic: ${error}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -435,31 +435,29 @@ text = "No spam"
|
||||||
|
|
||||||
[logging]
|
[logging]
|
||||||
|
|
||||||
# Available levels: debug, info, warning, error, fatal
|
# Available levels: trace, debug, info, warning, error, fatal
|
||||||
log_level = "debug"
|
log_level = "info" # For console output
|
||||||
|
|
||||||
log_file_path = "logs/versia.log"
|
|
||||||
|
|
||||||
[logging.types]
|
|
||||||
# Either pass a boolean
|
|
||||||
# requests = true
|
|
||||||
# Or a table with the following keys:
|
|
||||||
# requests_content = { level = "debug", log_file_path = "logs/requests.log" }
|
|
||||||
# Available types are: requests, responses, requests_content, filters
|
|
||||||
|
|
||||||
|
# [logging.file]
|
||||||
|
# path = "logs/versia.log"
|
||||||
|
# log_level = "info"
|
||||||
|
#
|
||||||
|
# [logging.file.rotation]
|
||||||
|
# max_size = 10_000_000 # 10 MB
|
||||||
|
# max_files = 10 # Keep 10 rotated files
|
||||||
|
#
|
||||||
# https://sentry.io support
|
# https://sentry.io support
|
||||||
# Uncomment to enable
|
|
||||||
# [logging.sentry]
|
# [logging.sentry]
|
||||||
# Sentry DSN for error logging
|
|
||||||
# dsn = "https://example.com"
|
# dsn = "https://example.com"
|
||||||
# debug = false
|
# debug = false
|
||||||
|
|
||||||
# sample_rate = 1.0
|
# sample_rate = 1.0
|
||||||
# traces_sample_rate = 1.0
|
# traces_sample_rate = 1.0
|
||||||
# Can also be regex
|
# Can also be regex
|
||||||
# trace_propagation_targets = []
|
# trace_propagation_targets = []
|
||||||
# max_breadcrumbs = 100
|
# max_breadcrumbs = 100
|
||||||
# environment = "production"
|
# environment = "production"
|
||||||
|
# log_level = "info"
|
||||||
|
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
# Whether to automatically load all plugins in the plugins directory
|
# Whether to automatically load all plugins in the plugins directory
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,8 @@
|
||||||
"@inquirer/confirm": "^5.1.12",
|
"@inquirer/confirm": "^5.1.12",
|
||||||
"@logtape/file": "^1.0.0",
|
"@logtape/file": "^1.0.0",
|
||||||
"@logtape/logtape": "^1.0.0",
|
"@logtape/logtape": "^1.0.0",
|
||||||
|
"@logtape/sentry": "^1.0.0",
|
||||||
|
"@logtape/otel": "^1.0.0",
|
||||||
"@scalar/hono-api-reference": "^0.9.6",
|
"@scalar/hono-api-reference": "^0.9.6",
|
||||||
"@sentry/bun": "^9.29.0",
|
"@sentry/bun": "^9.29.0",
|
||||||
"altcha-lib": "^1.3.0",
|
"altcha-lib": "^1.3.0",
|
||||||
|
|
@ -130,6 +132,7 @@
|
||||||
"es5-ext",
|
"es5-ext",
|
||||||
"esbuild",
|
"esbuild",
|
||||||
"msgpackr-extract",
|
"msgpackr-extract",
|
||||||
|
"protobufjs",
|
||||||
"sharp"
|
"sharp"
|
||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
@ -162,13 +165,12 @@
|
||||||
"@hackmd/markdown-it-task-lists": "catalog:",
|
"@hackmd/markdown-it-task-lists": "catalog:",
|
||||||
"@hono/zod-validator": "catalog:",
|
"@hono/zod-validator": "catalog:",
|
||||||
"@inquirer/confirm": "catalog:",
|
"@inquirer/confirm": "catalog:",
|
||||||
"@logtape/file": "catalog:",
|
|
||||||
"@logtape/logtape": "catalog:",
|
|
||||||
"@scalar/hono-api-reference": "catalog:",
|
"@scalar/hono-api-reference": "catalog:",
|
||||||
"@sentry/bun": "catalog:",
|
"@sentry/bun": "catalog:",
|
||||||
"@versia-server/config": "workspace:*",
|
"@versia-server/config": "workspace:*",
|
||||||
"@versia-server/kit": "workspace:*",
|
"@versia-server/kit": "workspace:*",
|
||||||
"@versia-server/tests": "workspace:*",
|
"@versia-server/tests": "workspace:*",
|
||||||
|
"@versia-server/logging": "workspace:*",
|
||||||
"@versia/client": "workspace:*",
|
"@versia/client": "workspace:*",
|
||||||
"@versia/sdk": "workspace:*",
|
"@versia/sdk": "workspace:*",
|
||||||
"altcha-lib": "catalog:",
|
"altcha-lib": "catalog:",
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { resolve } from "node:path";
|
import { resolve } from "node:path";
|
||||||
import { getLogger } from "@logtape/logtape";
|
|
||||||
import { Scalar } from "@scalar/hono-api-reference";
|
import { Scalar } from "@scalar/hono-api-reference";
|
||||||
import { config } from "@versia-server/config";
|
import { config } from "@versia-server/config";
|
||||||
import { ApiError } from "@versia-server/kit";
|
import { ApiError } from "@versia-server/kit";
|
||||||
|
import { serverLogger } from "@versia-server/logging";
|
||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
import { Hono } from "hono";
|
import { Hono } from "hono";
|
||||||
import { serveStatic } from "hono/bun";
|
import { serveStatic } from "hono/bun";
|
||||||
|
|
@ -13,8 +13,6 @@ import { secureHeaders } from "hono/secure-headers";
|
||||||
import { openAPISpecs } from "hono-openapi";
|
import { openAPISpecs } from "hono-openapi";
|
||||||
import { Youch } from "youch";
|
import { Youch } from "youch";
|
||||||
import { applyToHono } from "@/bull-board.ts";
|
import { applyToHono } from "@/bull-board.ts";
|
||||||
import { configureLoggers } from "@/loggers";
|
|
||||||
import { sentry } from "@/sentry";
|
|
||||||
import pkg from "~/package.json" with { type: "application/json" };
|
import pkg from "~/package.json" with { type: "application/json" };
|
||||||
import { PluginLoader } from "../../classes/plugin/loader.ts";
|
import { PluginLoader } from "../../classes/plugin/loader.ts";
|
||||||
import type { ApiRouteExports, HonoEnv } from "../../types/api.ts";
|
import type { ApiRouteExports, HonoEnv } from "../../types/api.ts";
|
||||||
|
|
@ -28,9 +26,6 @@ import { routes } from "./routes.ts";
|
||||||
import "zod-openapi/extend";
|
import "zod-openapi/extend";
|
||||||
|
|
||||||
export const appFactory = async (): Promise<Hono<HonoEnv>> => {
|
export const appFactory = async (): Promise<Hono<HonoEnv>> => {
|
||||||
await configureLoggers();
|
|
||||||
const serverLogger = getLogger("server");
|
|
||||||
|
|
||||||
const app = new Hono<HonoEnv>({
|
const app = new Hono<HonoEnv>({
|
||||||
strict: false,
|
strict: false,
|
||||||
});
|
});
|
||||||
|
|
@ -124,7 +119,7 @@ export const appFactory = async (): Promise<Hono<HonoEnv>> => {
|
||||||
config.plugins?.overrides.disabled,
|
config.plugins?.overrides.disabled,
|
||||||
);
|
);
|
||||||
|
|
||||||
await PluginLoader.addToApp(plugins, app, serverLogger);
|
await PluginLoader.addToApp(plugins, app);
|
||||||
|
|
||||||
const time2 = performance.now();
|
const time2 = performance.now();
|
||||||
|
|
||||||
|
|
@ -193,7 +188,6 @@ export const appFactory = async (): Promise<Hono<HonoEnv>> => {
|
||||||
const youch = new Youch();
|
const youch = new Youch();
|
||||||
console.error(await youch.toANSI(error));
|
console.error(await youch.toANSI(error));
|
||||||
|
|
||||||
sentry?.captureException(error);
|
|
||||||
return c.json(
|
return c.json(
|
||||||
{
|
{
|
||||||
error: "A server error occured",
|
error: "A server error occured",
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import process from "node:process";
|
import process from "node:process";
|
||||||
import { config } from "@versia-server/config";
|
import { config } from "@versia-server/config";
|
||||||
import { Youch } from "youch";
|
import { Youch } from "youch";
|
||||||
import { sentry } from "@/sentry";
|
|
||||||
import { createServer } from "@/server";
|
import { createServer } from "@/server";
|
||||||
import { appFactory } from "./app.ts";
|
import { appFactory } from "./app.ts";
|
||||||
|
|
||||||
|
|
@ -16,6 +15,5 @@ process.on("uncaughtException", async (error) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
await import("./setup.ts");
|
await import("./setup.ts");
|
||||||
sentry?.captureMessage("Server started", "info");
|
|
||||||
|
|
||||||
createServer(config, await appFactory());
|
createServer(config, await appFactory());
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
import { getLogger } from "@logtape/logtape";
|
|
||||||
import { config } from "@versia-server/config";
|
import { config } from "@versia-server/config";
|
||||||
import { ApiError } from "@versia-server/kit";
|
import { ApiError } from "@versia-server/kit";
|
||||||
|
import { serverLogger } from "@versia-server/logging";
|
||||||
import type { SocketAddress } from "bun";
|
import type { SocketAddress } from "bun";
|
||||||
import { createMiddleware } from "hono/factory";
|
import { createMiddleware } from "hono/factory";
|
||||||
import { matches } from "ip-matching";
|
import { matches } from "ip-matching";
|
||||||
import { sentry } from "@/sentry";
|
|
||||||
|
|
||||||
export const ipBans = createMiddleware(async (context, next) => {
|
export const ipBans = createMiddleware(async (context, next) => {
|
||||||
// Check for banned IPs
|
// Check for banned IPs
|
||||||
|
|
@ -22,11 +21,8 @@ export const ipBans = createMiddleware(async (context, next) => {
|
||||||
throw new ApiError(403, "Forbidden");
|
throw new ApiError(403, "Forbidden");
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const logger = getLogger("server");
|
serverLogger.error`Error while parsing banned IP "${ip}" `;
|
||||||
|
serverLogger.error`${e}`;
|
||||||
logger.error`Error while parsing banned IP "${ip}" `;
|
|
||||||
logger.error`${e}`;
|
|
||||||
sentry?.captureException(e);
|
|
||||||
|
|
||||||
return context.json(
|
return context.json(
|
||||||
{ error: `A server error occured: ${(e as Error).message}` },
|
{ error: `A server error occured: ${(e as Error).message}` },
|
||||||
|
|
|
||||||
|
|
@ -1,37 +1,26 @@
|
||||||
import { getLogger } from "@logtape/logtape";
|
import { serverLogger } from "@versia-server/logging";
|
||||||
import { config } from "@versia-server/config";
|
|
||||||
import { SHA256 } from "bun";
|
import { SHA256 } from "bun";
|
||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
import { createMiddleware } from "hono/factory";
|
import { createMiddleware } from "hono/factory";
|
||||||
|
|
||||||
export const logger = createMiddleware(async (context, next) => {
|
export const logger = createMiddleware(async (context, next) => {
|
||||||
if (config.logging.types.requests) {
|
const body = await context.req.raw.clone().text();
|
||||||
const serverLogger = getLogger("server");
|
|
||||||
const body = await context.req.raw.clone().text();
|
|
||||||
|
|
||||||
const urlAndMethod = `${chalk.green(context.req.method)} ${chalk.blue(context.req.url)}`;
|
const urlAndMethod = `${chalk.green(context.req.method)} ${chalk.blue(context.req.url)}`;
|
||||||
|
|
||||||
const hash = `${chalk.bold("Hash")}: ${chalk.yellow(
|
const hash = `${chalk.bold("Hash")}: ${chalk.yellow(
|
||||||
new SHA256().update(body).digest("hex"),
|
new SHA256().update(body).digest("hex"),
|
||||||
)}`;
|
)}`;
|
||||||
|
|
||||||
const headers = `${chalk.bold("Headers")}:\n${Array.from(
|
const headers = `${chalk.bold("Headers")}:\n${Array.from(
|
||||||
context.req.raw.headers.entries(),
|
context.req.raw.headers.entries(),
|
||||||
)
|
)
|
||||||
.map(
|
.map(([key, value]) => ` - ${chalk.cyan(key)}: ${chalk.white(value)}`)
|
||||||
([key, value]) =>
|
.join("\n")}`;
|
||||||
` - ${chalk.cyan(key)}: ${chalk.white(value)}`,
|
|
||||||
)
|
|
||||||
.join("\n")}`;
|
|
||||||
|
|
||||||
const bodyLog = `${chalk.bold("Body")}: ${chalk.gray(body)}`;
|
const bodyLog = `${chalk.bold("Body")}: ${chalk.gray(body)}`;
|
||||||
|
|
||||||
if (config.logging.types.requests_content) {
|
serverLogger.debug`${urlAndMethod}\n${hash}\n${headers}\n${bodyLog}`;
|
||||||
serverLogger.debug`${urlAndMethod}\n${hash}\n${headers}\n${bodyLog}`;
|
|
||||||
} else {
|
|
||||||
serverLogger.debug`${urlAndMethod}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await next();
|
await next();
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -45,9 +45,9 @@
|
||||||
"@versia-server/config": "workspace:*",
|
"@versia-server/config": "workspace:*",
|
||||||
"@versia-server/tests": "workspace:*",
|
"@versia-server/tests": "workspace:*",
|
||||||
"@versia-server/kit": "workspace:*",
|
"@versia-server/kit": "workspace:*",
|
||||||
|
"@versia-server/logging": "workspace:*",
|
||||||
"@versia/client": "workspace:*",
|
"@versia/client": "workspace:*",
|
||||||
"@versia/sdk": "workspace:*",
|
"@versia/sdk": "workspace:*",
|
||||||
"@logtape/logtape": "catalog:",
|
|
||||||
"youch": "catalog:",
|
"youch": "catalog:",
|
||||||
"hono": "catalog:",
|
"hono": "catalog:",
|
||||||
"hono-openapi": "catalog:",
|
"hono-openapi": "catalog:",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { getLogger } from "@logtape/logtape";
|
|
||||||
import { apiRoute } from "@versia-server/kit/api";
|
import { apiRoute } from "@versia-server/kit/api";
|
||||||
|
import { federationMessagingLogger } from "@versia-server/logging";
|
||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
import { describeRoute } from "hono-openapi";
|
import { describeRoute } from "hono-openapi";
|
||||||
|
|
||||||
|
|
@ -19,8 +19,7 @@ export default apiRoute((app) =>
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const content = await context.req.text();
|
const content = await context.req.text();
|
||||||
|
|
||||||
getLogger(["federation", "messaging"])
|
federationMessagingLogger.info`Received message via ${chalk.bold("Instance Messaging")}:\n${content}`;
|
||||||
.info`Received message via ${chalk.bold("Instance Messaging")}:\n${content}`;
|
|
||||||
|
|
||||||
return context.text("", 200);
|
return context.text("", 200);
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import { getLogger } from "@logtape/logtape";
|
|
||||||
import { FederationRequester } from "@versia/sdk/http";
|
import { FederationRequester } from "@versia/sdk/http";
|
||||||
import { WebFingerSchema } from "@versia/sdk/schemas";
|
import { WebFingerSchema } from "@versia/sdk/schemas";
|
||||||
import { config } from "@versia-server/config";
|
import { config } from "@versia-server/config";
|
||||||
|
|
@ -8,6 +7,7 @@ import { User } from "@versia-server/kit/db";
|
||||||
import { parseUserAddress } from "@versia-server/kit/parsers";
|
import { parseUserAddress } from "@versia-server/kit/parsers";
|
||||||
import { uuid, webfingerMention } from "@versia-server/kit/regex";
|
import { uuid, webfingerMention } from "@versia-server/kit/regex";
|
||||||
import { Users } from "@versia-server/kit/tables";
|
import { Users } from "@versia-server/kit/tables";
|
||||||
|
import { federationBridgeLogger } from "@versia-server/logging";
|
||||||
import { and, eq, isNull } from "drizzle-orm";
|
import { and, eq, isNull } from "drizzle-orm";
|
||||||
import { describeRoute } from "hono-openapi";
|
import { describeRoute } from "hono-openapi";
|
||||||
import { resolver, validator } from "hono-openapi/zod";
|
import { resolver, validator } from "hono-openapi/zod";
|
||||||
|
|
@ -90,8 +90,7 @@ export default apiRoute((app) =>
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const error = e as ApiError;
|
const error = e as ApiError;
|
||||||
|
|
||||||
getLogger(["federation", "bridge"])
|
federationBridgeLogger.error`Error from bridge: ${error.message}`;
|
||||||
.error`Error from bridge: ${error.message}`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,11 @@
|
||||||
import { getLogger } from "@logtape/logtape";
|
|
||||||
import { config } from "@versia-server/config";
|
import { config } from "@versia-server/config";
|
||||||
import { Note, setupDatabase } from "@versia-server/kit/db";
|
import { Note, setupDatabase } from "@versia-server/kit/db";
|
||||||
import { connection } from "@versia-server/kit/redis";
|
import { connection } from "@versia-server/kit/redis";
|
||||||
import { configureLoggers } from "@/loggers";
|
import { serverLogger } from "@versia-server/logging";
|
||||||
import { searchManager } from "../../classes/search/search-manager.ts";
|
import { searchManager } from "../../classes/search/search-manager.ts";
|
||||||
|
|
||||||
const timeAtStart = performance.now();
|
const timeAtStart = performance.now();
|
||||||
|
|
||||||
await configureLoggers();
|
|
||||||
|
|
||||||
const serverLogger = getLogger("server");
|
|
||||||
|
|
||||||
console.info(`
|
console.info(`
|
||||||
██╗ ██╗███████╗██████╗ ███████╗██╗ █████╗
|
██╗ ██╗███████╗██████╗ ███████╗██╗ █████╗
|
||||||
██║ ██║██╔════╝██╔══██╗██╔════╝██║██╔══██╗
|
██║ ██║██╔════╝██╔══██╗██╔════╝██║██╔══██╗
|
||||||
|
|
|
||||||
|
|
@ -716,34 +716,35 @@ export const ConfigSchema = z
|
||||||
admin: z.array(z.nativeEnum(RolePermission)).default(ADMIN_ROLES),
|
admin: z.array(z.nativeEnum(RolePermission)).default(ADMIN_ROLES),
|
||||||
}),
|
}),
|
||||||
logging: z.strictObject({
|
logging: z.strictObject({
|
||||||
types: z.record(
|
file: z
|
||||||
z.enum([
|
.strictObject({
|
||||||
"requests",
|
path: z.string().default("logs/versia.log"),
|
||||||
"responses",
|
rotation: z
|
||||||
"requests_content",
|
.strictObject({
|
||||||
"filters",
|
max_size: z
|
||||||
]),
|
.number()
|
||||||
z
|
.int()
|
||||||
.boolean()
|
.nonnegative()
|
||||||
.default(false)
|
.default(10_000_000), // 10 MB
|
||||||
.or(
|
max_files: z
|
||||||
z.strictObject({
|
.number()
|
||||||
level: z
|
.int()
|
||||||
.enum([
|
.nonnegative()
|
||||||
"debug",
|
.default(10),
|
||||||
"info",
|
})
|
||||||
"warning",
|
.optional(),
|
||||||
"error",
|
log_level: z
|
||||||
"fatal",
|
.enum([
|
||||||
])
|
"trace",
|
||||||
.default("info"),
|
"debug",
|
||||||
log_file_path: z.string().optional(),
|
"info",
|
||||||
}),
|
"warning",
|
||||||
),
|
"error",
|
||||||
),
|
"fatal",
|
||||||
log_level: z
|
])
|
||||||
.enum(["debug", "info", "warning", "error", "fatal"])
|
.default("info"),
|
||||||
.default("info"),
|
})
|
||||||
|
.optional(),
|
||||||
sentry: z
|
sentry: z
|
||||||
.strictObject({
|
.strictObject({
|
||||||
dsn: url,
|
dsn: url,
|
||||||
|
|
@ -753,9 +754,21 @@ export const ConfigSchema = z
|
||||||
trace_propagation_targets: z.array(z.string()).default([]),
|
trace_propagation_targets: z.array(z.string()).default([]),
|
||||||
max_breadcrumbs: z.number().default(100),
|
max_breadcrumbs: z.number().default(100),
|
||||||
environment: z.string().optional(),
|
environment: z.string().optional(),
|
||||||
|
log_level: z
|
||||||
|
.enum([
|
||||||
|
"trace",
|
||||||
|
"debug",
|
||||||
|
"info",
|
||||||
|
"warning",
|
||||||
|
"error",
|
||||||
|
"fatal",
|
||||||
|
])
|
||||||
|
.default("info"),
|
||||||
})
|
})
|
||||||
.optional(),
|
.optional(),
|
||||||
log_file_path: z.string().default("logs/versia.log"),
|
log_level: z
|
||||||
|
.enum(["trace", "debug", "info", "warning", "error", "fatal"])
|
||||||
|
.default("info"),
|
||||||
}),
|
}),
|
||||||
debug: z
|
debug: z
|
||||||
.strictObject({
|
.strictObject({
|
||||||
|
|
|
||||||
56
packages/logging/formatter.ts
Normal file
56
packages/logging/formatter.ts
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
import type { LogLevel, LogRecord } from "@logtape/logtape";
|
||||||
|
import chalk, { type ChalkInstance } from "chalk";
|
||||||
|
|
||||||
|
const levelAbbreviations: Record<LogLevel, string> = {
|
||||||
|
debug: "DBG",
|
||||||
|
info: "INF",
|
||||||
|
warning: "WRN",
|
||||||
|
error: "ERR",
|
||||||
|
fatal: "FTL",
|
||||||
|
trace: "TRC",
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The styles for the log level in the console.
|
||||||
|
*/
|
||||||
|
const logLevelStyles: Record<LogLevel, ChalkInstance> = {
|
||||||
|
debug: chalk.white.bgGray,
|
||||||
|
info: chalk.black.bgWhite,
|
||||||
|
warning: chalk.black.bgYellow,
|
||||||
|
error: chalk.white.bgRed,
|
||||||
|
fatal: chalk.white.bgRedBright,
|
||||||
|
trace: chalk.white.bgBlue,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pretty colored console formatter.
|
||||||
|
*
|
||||||
|
* @param record The log record to format.
|
||||||
|
* @returns The formatted log record, as an array of arguments for
|
||||||
|
* {@link console.log}.
|
||||||
|
*/
|
||||||
|
export function consoleFormatter(record: LogRecord): string[] {
|
||||||
|
const msg = record.message.join("");
|
||||||
|
const date = new Date(record.timestamp);
|
||||||
|
const time = `${date.getUTCHours().toString().padStart(2, "0")}:${date
|
||||||
|
.getUTCMinutes()
|
||||||
|
.toString()
|
||||||
|
.padStart(
|
||||||
|
2,
|
||||||
|
"0",
|
||||||
|
)}:${date.getUTCSeconds().toString().padStart(2, "0")}.${date
|
||||||
|
.getUTCMilliseconds()
|
||||||
|
.toString()
|
||||||
|
.padStart(3, "0")}`;
|
||||||
|
|
||||||
|
const formattedTime = chalk.gray(time);
|
||||||
|
const formattedLevel = logLevelStyles[record.level](
|
||||||
|
levelAbbreviations[record.level],
|
||||||
|
);
|
||||||
|
const formattedCategory = chalk.gray(record.category.join("\xb7"));
|
||||||
|
const formattedMsg = chalk.reset(msg);
|
||||||
|
|
||||||
|
return [
|
||||||
|
`${formattedTime} ${formattedLevel} ${formattedCategory} ${formattedMsg}`,
|
||||||
|
];
|
||||||
|
}
|
||||||
158
packages/logging/index.ts
Normal file
158
packages/logging/index.ts
Normal file
|
|
@ -0,0 +1,158 @@
|
||||||
|
import { mkdir } from "node:fs/promises";
|
||||||
|
import { dirname } from "node:path";
|
||||||
|
import { getFileSink, getRotatingFileSink } from "@logtape/file";
|
||||||
|
import {
|
||||||
|
configure,
|
||||||
|
getConsoleSink,
|
||||||
|
getLevelFilter,
|
||||||
|
getLogger,
|
||||||
|
type Sink,
|
||||||
|
withFilter,
|
||||||
|
} from "@logtape/logtape";
|
||||||
|
import { getSentrySink } from "@logtape/sentry";
|
||||||
|
import * as Sentry from "@sentry/bun";
|
||||||
|
import { config } from "@versia-server/config";
|
||||||
|
import { env } from "bun";
|
||||||
|
import pkg from "../../package.json" with { type: "json" };
|
||||||
|
import { consoleFormatter } from "./formatter.ts";
|
||||||
|
|
||||||
|
if (config.logging.file?.path) {
|
||||||
|
// config.logging.file.path is a path to a file, create the directory if it doesn't exist
|
||||||
|
await mkdir(dirname(config.logging.file.path), { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all configured sinks depending on the configuration.
|
||||||
|
*/
|
||||||
|
const getSinks = (): Record<"file" | "console" | "sentry", Sink> => {
|
||||||
|
const sinks: Record<string, Sink> = {};
|
||||||
|
|
||||||
|
if (config.logging.file) {
|
||||||
|
if (config.logging.file.rotation) {
|
||||||
|
sinks.file = getRotatingFileSink(config.logging.file.path, {
|
||||||
|
maxFiles: config.logging.file.rotation.max_files,
|
||||||
|
maxSize: config.logging.file.rotation.max_size,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
sinks.file = getFileSink(config.logging.file.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
sinks.file = withFilter(
|
||||||
|
sinks.file,
|
||||||
|
getLevelFilter(config.logging.file.log_level),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.logging.sentry) {
|
||||||
|
sinks.sentry = getSentrySink(
|
||||||
|
Sentry.init({
|
||||||
|
dsn: config.logging.sentry.dsn.origin,
|
||||||
|
debug: config.logging.sentry.debug,
|
||||||
|
sampleRate: config.logging.sentry.sample_rate,
|
||||||
|
maxBreadcrumbs: config.logging.sentry.max_breadcrumbs,
|
||||||
|
tracesSampleRate: config.logging.sentry.traces_sample_rate,
|
||||||
|
environment: config.logging.sentry.environment,
|
||||||
|
tracePropagationTargets:
|
||||||
|
config.logging.sentry.trace_propagation_targets,
|
||||||
|
release: env.GIT_COMMIT
|
||||||
|
? `${pkg.version}-${env.GIT_COMMIT}`
|
||||||
|
: pkg.version,
|
||||||
|
integrations: [Sentry.extraErrorDataIntegration()],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
sinks.sentry = withFilter(
|
||||||
|
sinks.sentry,
|
||||||
|
getLevelFilter(config.logging.sentry.log_level),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
sinks.console = getConsoleSink({
|
||||||
|
formatter: consoleFormatter,
|
||||||
|
});
|
||||||
|
|
||||||
|
sinks.console = withFilter(
|
||||||
|
sinks.console,
|
||||||
|
getLevelFilter(config.logging.log_level),
|
||||||
|
);
|
||||||
|
|
||||||
|
return sinks;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getSinkNames = (): ("file" | "console" | "sentry")[] => {
|
||||||
|
const names = [] as ("file" | "console" | "sentry")[];
|
||||||
|
|
||||||
|
if (config.logging.file) {
|
||||||
|
names.push("file");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.logging.sentry) {
|
||||||
|
names.push("sentry");
|
||||||
|
}
|
||||||
|
|
||||||
|
names.push("console");
|
||||||
|
|
||||||
|
return names;
|
||||||
|
};
|
||||||
|
|
||||||
|
await configure({
|
||||||
|
reset: true,
|
||||||
|
sinks: getSinks(),
|
||||||
|
loggers: [
|
||||||
|
{
|
||||||
|
category: "server",
|
||||||
|
sinks: getSinkNames(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: ["federation", "inbox"],
|
||||||
|
sinks: getSinkNames(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: ["federation", "delivery"],
|
||||||
|
sinks: getSinkNames(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: ["federation", "bridge"],
|
||||||
|
sinks: getSinkNames(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: ["federation", "resolvers"],
|
||||||
|
sinks: getSinkNames(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: ["federation", "messaging"],
|
||||||
|
sinks: getSinkNames(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: "database",
|
||||||
|
sinks: getSinkNames(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: "webfinger",
|
||||||
|
sinks: getSinkNames(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: "sonic",
|
||||||
|
sinks: getSinkNames(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: ["logtape", "meta"],
|
||||||
|
lowestLevel: "error",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: "plugin",
|
||||||
|
sinks: getSinkNames(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
export const serverLogger = getLogger("server");
|
||||||
|
export const federationInboxLogger = getLogger(["federation", "inbox"]);
|
||||||
|
export const federationDeliveryLogger = getLogger(["federation", "delivery"]);
|
||||||
|
export const federationBridgeLogger = getLogger(["federation", "bridge"]);
|
||||||
|
export const federationResolversLogger = getLogger(["federation", "resolvers"]);
|
||||||
|
export const federationMessagingLogger = getLogger(["federation", "messaging"]);
|
||||||
|
export const databaseLogger = getLogger("database");
|
||||||
|
export const webfingerLogger = getLogger("webfinger");
|
||||||
|
export const sonicLogger = getLogger("sonic");
|
||||||
|
export const pluginLogger = getLogger("plugin");
|
||||||
22
packages/logging/package.json
Normal file
22
packages/logging/package.json
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"name": "@versia-server/logging",
|
||||||
|
"module": "index.ts",
|
||||||
|
"type": "module",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"private": true,
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"import": "./index.ts",
|
||||||
|
"default": "./index.ts"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@versia-server/config": "workspace:*",
|
||||||
|
"@logtape/logtape": "catalog:",
|
||||||
|
"@logtape/file": "catalog:",
|
||||||
|
"@logtape/sentry": "catalog:",
|
||||||
|
"@logtape/otel": "catalog:",
|
||||||
|
"@sentry/bun": "catalog:",
|
||||||
|
"chalk": "catalog:"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import type { Hook } from "@hono/zod-validator";
|
import type { Hook } from "@hono/zod-validator";
|
||||||
import { getLogger } from "@logtape/logtape";
|
|
||||||
import type { RolePermission } from "@versia/client/schemas";
|
import type { RolePermission } from "@versia/client/schemas";
|
||||||
import { config } from "@versia-server/config";
|
import { config } from "@versia-server/config";
|
||||||
|
import { serverLogger } from "@versia-server/logging";
|
||||||
import { extractParams, verifySolution } from "altcha-lib";
|
import { extractParams, verifySolution } from "altcha-lib";
|
||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
import { eq, type SQL } from "drizzle-orm";
|
import { eq, type SQL } from "drizzle-orm";
|
||||||
|
|
@ -418,7 +418,6 @@ export const jsonOrForm = (): MiddlewareHandler<HonoEnv> => {
|
||||||
|
|
||||||
export const debugResponse = async (res: Response): Promise<void> => {
|
export const debugResponse = async (res: Response): Promise<void> => {
|
||||||
const body = await res.clone().text();
|
const body = await res.clone().text();
|
||||||
const logger = getLogger("server");
|
|
||||||
|
|
||||||
const status = `${chalk.bold("Status")}: ${chalk.green(res.status)}`;
|
const status = `${chalk.bold("Status")}: ${chalk.green(res.status)}`;
|
||||||
|
|
||||||
|
|
@ -430,9 +429,5 @@ export const debugResponse = async (res: Response): Promise<void> => {
|
||||||
|
|
||||||
const bodyLog = `${chalk.bold("Body")}: ${chalk.gray(body)}`;
|
const bodyLog = `${chalk.bold("Body")}: ${chalk.gray(body)}`;
|
||||||
|
|
||||||
if (config.logging.types.requests_content) {
|
serverLogger.debug`${status}\n${headers}\n${bodyLog}`;
|
||||||
logger.debug`${status}\n${headers}\n${bodyLog}`;
|
|
||||||
} else {
|
|
||||||
logger.debug`${status}`;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
import { getLogger } from "@logtape/logtape";
|
|
||||||
import * as VersiaEntities from "@versia/sdk/entities";
|
import * as VersiaEntities from "@versia/sdk/entities";
|
||||||
import { config } from "@versia-server/config";
|
import { config } from "@versia-server/config";
|
||||||
import { ApiError } from "@versia-server/kit";
|
import { ApiError } from "@versia-server/kit";
|
||||||
import { db } from "@versia-server/kit/db";
|
import { db } from "@versia-server/kit/db";
|
||||||
import { Instances } from "@versia-server/kit/tables";
|
import { Instances } from "@versia-server/kit/tables";
|
||||||
|
import {
|
||||||
|
federationMessagingLogger,
|
||||||
|
federationResolversLogger,
|
||||||
|
} from "@versia-server/logging";
|
||||||
import { randomUUIDv7 } from "bun";
|
import { randomUUIDv7 } from "bun";
|
||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
import {
|
import {
|
||||||
|
|
@ -175,9 +178,6 @@ export class Instance extends BaseInterface<typeof Instances> {
|
||||||
const wellKnownUrl = new URL("/.well-known/nodeinfo", origin);
|
const wellKnownUrl = new URL("/.well-known/nodeinfo", origin);
|
||||||
|
|
||||||
// Go to endpoint, then follow the links to the actual metadata
|
// Go to endpoint, then follow the links to the actual metadata
|
||||||
|
|
||||||
const logger = getLogger(["federation", "resolvers"]);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { json, ok, status } = await fetch(wellKnownUrl, {
|
const { json, ok, status } = await fetch(wellKnownUrl, {
|
||||||
// @ts-expect-error Bun extension
|
// @ts-expect-error Bun extension
|
||||||
|
|
@ -185,7 +185,7 @@ export class Instance extends BaseInterface<typeof Instances> {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
logger.error`Failed to fetch ActivityPub metadata for instance ${chalk.bold(
|
federationResolversLogger.error`Failed to fetch ActivityPub metadata for instance ${chalk.bold(
|
||||||
origin,
|
origin,
|
||||||
)} - HTTP ${status}`;
|
)} - HTTP ${status}`;
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -196,7 +196,7 @@ export class Instance extends BaseInterface<typeof Instances> {
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!wellKnown.links) {
|
if (!wellKnown.links) {
|
||||||
logger.error`Failed to fetch ActivityPub metadata for instance ${chalk.bold(
|
federationResolversLogger.error`Failed to fetch ActivityPub metadata for instance ${chalk.bold(
|
||||||
origin,
|
origin,
|
||||||
)} - No links found`;
|
)} - No links found`;
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -209,7 +209,7 @@ export class Instance extends BaseInterface<typeof Instances> {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!metadataUrl) {
|
if (!metadataUrl) {
|
||||||
logger.error`Failed to fetch ActivityPub metadata for instance ${chalk.bold(
|
federationResolversLogger.error`Failed to fetch ActivityPub metadata for instance ${chalk.bold(
|
||||||
origin,
|
origin,
|
||||||
)} - No metadata URL found`;
|
)} - No metadata URL found`;
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -225,7 +225,7 @@ export class Instance extends BaseInterface<typeof Instances> {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!ok2) {
|
if (!ok2) {
|
||||||
logger.error`Failed to fetch ActivityPub metadata for instance ${chalk.bold(
|
federationResolversLogger.error`Failed to fetch ActivityPub metadata for instance ${chalk.bold(
|
||||||
origin,
|
origin,
|
||||||
)} - HTTP ${status2}`;
|
)} - HTTP ${status2}`;
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -264,7 +264,7 @@ export class Instance extends BaseInterface<typeof Instances> {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error`Failed to fetch ActivityPub metadata for instance ${chalk.bold(
|
federationResolversLogger.error`Failed to fetch ActivityPub metadata for instance ${chalk.bold(
|
||||||
origin,
|
origin,
|
||||||
)} - Error! ${error}`;
|
)} - Error! ${error}`;
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -312,14 +312,12 @@ export class Instance extends BaseInterface<typeof Instances> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async updateFromRemote(): Promise<Instance> {
|
public async updateFromRemote(): Promise<Instance> {
|
||||||
const logger = getLogger(["federation", "resolvers"]);
|
|
||||||
|
|
||||||
const output = await Instance.fetchMetadata(
|
const output = await Instance.fetchMetadata(
|
||||||
new URL(`https://${this.data.baseUrl}`),
|
new URL(`https://${this.data.baseUrl}`),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!output) {
|
if (!output) {
|
||||||
logger.error`Failed to update instance ${chalk.bold(
|
federationResolversLogger.error`Failed to update instance ${chalk.bold(
|
||||||
this.data.baseUrl,
|
this.data.baseUrl,
|
||||||
)}`;
|
)}`;
|
||||||
throw new Error("Failed to update instance");
|
throw new Error("Failed to update instance");
|
||||||
|
|
@ -341,12 +339,10 @@ export class Instance extends BaseInterface<typeof Instances> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async sendMessage(content: string): Promise<void> {
|
public async sendMessage(content: string): Promise<void> {
|
||||||
const logger = getLogger(["federation", "messaging"]);
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!this.data.extensions?.["pub.versia:instance_messaging"]?.endpoint
|
!this.data.extensions?.["pub.versia:instance_messaging"]?.endpoint
|
||||||
) {
|
) {
|
||||||
logger.info`Instance ${chalk.gray(
|
federationMessagingLogger.info`Instance ${chalk.gray(
|
||||||
this.data.baseUrl,
|
this.data.baseUrl,
|
||||||
)} does not support Instance Messaging, skipping message`;
|
)} does not support Instance Messaging, skipping message`;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import { getLogger } from "@logtape/logtape";
|
|
||||||
import type {
|
import type {
|
||||||
Account,
|
Account,
|
||||||
Mention as MentionSchema,
|
Mention as MentionSchema,
|
||||||
|
|
@ -29,6 +28,10 @@ import {
|
||||||
Users,
|
Users,
|
||||||
UserToPinnedNotes,
|
UserToPinnedNotes,
|
||||||
} from "@versia-server/kit/tables";
|
} from "@versia-server/kit/tables";
|
||||||
|
import {
|
||||||
|
federationDeliveryLogger,
|
||||||
|
federationResolversLogger,
|
||||||
|
} from "@versia-server/logging";
|
||||||
import { password as bunPassword, randomUUIDv7 } from "bun";
|
import { password as bunPassword, randomUUIDv7 } from "bun";
|
||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
import {
|
import {
|
||||||
|
|
@ -49,7 +52,6 @@ import { htmlToText } from "html-to-text";
|
||||||
import type { z } from "zod";
|
import type { z } from "zod";
|
||||||
import { getBestContentType } from "@/content_types";
|
import { getBestContentType } from "@/content_types";
|
||||||
import { randomString } from "@/math";
|
import { randomString } from "@/math";
|
||||||
import { sentry } from "@/sentry";
|
|
||||||
import { searchManager } from "~/classes/search/search-manager";
|
import { searchManager } from "~/classes/search/search-manager";
|
||||||
import type { HttpVerb, KnownEntity } from "~/types/api.ts";
|
import type { HttpVerb, KnownEntity } from "~/types/api.ts";
|
||||||
import {
|
import {
|
||||||
|
|
@ -1165,8 +1167,7 @@ export class User extends BaseInterface<typeof Users, UserWithRelations> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async resolve(uri: URL): Promise<User | null> {
|
public static async resolve(uri: URL): Promise<User | null> {
|
||||||
getLogger(["federation", "resolvers"])
|
federationResolversLogger.debug`Resolving user ${chalk.gray(uri)}`;
|
||||||
.debug`Resolving user ${chalk.gray(uri)}`;
|
|
||||||
// Check if user not already in database
|
// Check if user not already in database
|
||||||
const foundUser = await User.fromSql(eq(Users.uri, uri.href));
|
const foundUser = await User.fromSql(eq(Users.uri, uri.href));
|
||||||
|
|
||||||
|
|
@ -1187,8 +1188,7 @@ export class User extends BaseInterface<typeof Users, UserWithRelations> {
|
||||||
return await User.fromId(userUuid[0]);
|
return await User.fromId(userUuid[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
getLogger(["federation", "resolvers"])
|
federationResolversLogger.debug`User not found in database, fetching from remote`;
|
||||||
.debug`User not found in database, fetching from remote`;
|
|
||||||
|
|
||||||
return User.fromVersia(uri);
|
return User.fromVersia(uri);
|
||||||
}
|
}
|
||||||
|
|
@ -1419,11 +1419,10 @@ export class User extends BaseInterface<typeof Users, UserWithRelations> {
|
||||||
entity,
|
entity,
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
getLogger(["federation", "delivery"]).error`Federating ${chalk.gray(
|
federationDeliveryLogger.error`Federating ${chalk.gray(
|
||||||
entity.data.type,
|
entity.data.type,
|
||||||
)} to ${user.uri} ${chalk.bold.red("failed")}`;
|
)} to ${user.uri} ${chalk.bold.red("failed")}`;
|
||||||
getLogger(["federation", "delivery"]).error`${e}`;
|
federationDeliveryLogger.error`${e}`;
|
||||||
sentry?.captureException(e);
|
|
||||||
|
|
||||||
return { ok: false };
|
return { ok: false };
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,9 +41,9 @@
|
||||||
"chalk": "catalog:",
|
"chalk": "catalog:",
|
||||||
"@versia/client": "workspace:*",
|
"@versia/client": "workspace:*",
|
||||||
"@versia-server/config": "workspace:*",
|
"@versia-server/config": "workspace:*",
|
||||||
|
"@versia-server/logging": "workspace:*",
|
||||||
"@versia/sdk": "workspace:*",
|
"@versia/sdk": "workspace:*",
|
||||||
"html-to-text": "catalog:",
|
"html-to-text": "catalog:",
|
||||||
"@logtape/logtape": "catalog:",
|
|
||||||
"sharp": "catalog:",
|
"sharp": "catalog:",
|
||||||
"magic-regexp": "catalog:",
|
"magic-regexp": "catalog:",
|
||||||
"altcha-lib": "catalog:",
|
"altcha-lib": "catalog:",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { getLogger } from "@logtape/logtape";
|
|
||||||
import { config } from "@versia-server/config";
|
import { config } from "@versia-server/config";
|
||||||
|
import { databaseLogger } from "@versia-server/logging";
|
||||||
import { SQL } from "bun";
|
import { SQL } from "bun";
|
||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
import { type BunSQLDatabase, drizzle } from "drizzle-orm/bun-sql";
|
import { type BunSQLDatabase, drizzle } from "drizzle-orm/bun-sql";
|
||||||
|
|
@ -40,8 +40,6 @@ export const db =
|
||||||
: drizzle(primaryDb, { schema });
|
: drizzle(primaryDb, { schema });
|
||||||
|
|
||||||
export const setupDatabase = async (info = true): Promise<void> => {
|
export const setupDatabase = async (info = true): Promise<void> => {
|
||||||
const logger = getLogger("database");
|
|
||||||
|
|
||||||
for (const dbPool of [primaryDb, ...replicas]) {
|
for (const dbPool of [primaryDb, ...replicas]) {
|
||||||
try {
|
try {
|
||||||
await dbPool.connect();
|
await dbPool.connect();
|
||||||
|
|
@ -53,7 +51,7 @@ export const setupDatabase = async (info = true): Promise<void> => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.fatal`Failed to connect to database ${chalk.bold(
|
databaseLogger.fatal`Failed to connect to database ${chalk.bold(
|
||||||
// Index of the database in the array
|
// Index of the database in the array
|
||||||
replicas.indexOf(dbPool) === -1
|
replicas.indexOf(dbPool) === -1
|
||||||
? "primary"
|
? "primary"
|
||||||
|
|
@ -65,17 +63,17 @@ export const setupDatabase = async (info = true): Promise<void> => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Migrate the database
|
// Migrate the database
|
||||||
info && logger.info`Migrating database...`;
|
info && databaseLogger.info`Migrating database...`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await migrate(db, {
|
await migrate(db, {
|
||||||
migrationsFolder: "./packages/plugin-kit/tables/migrations",
|
migrationsFolder: "./packages/plugin-kit/tables/migrations",
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.fatal`Failed to migrate database. Please check your configuration.`;
|
databaseLogger.fatal`Failed to migrate database. Please check your configuration.`;
|
||||||
|
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
info && logger.info`Database migrated`;
|
info && databaseLogger.info`Database migrated`;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import process from "node:process";
|
import process from "node:process";
|
||||||
import { getLogger } from "@logtape/logtape";
|
import { serverLogger } from "@versia-server/logging";
|
||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
import { sentry } from "@/sentry";
|
|
||||||
import { workers } from "./workers.ts";
|
import { workers } from "./workers.ts";
|
||||||
|
|
||||||
process.on("SIGINT", () => {
|
process.on("SIGINT", () => {
|
||||||
|
|
@ -9,9 +8,6 @@ process.on("SIGINT", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
await import("./setup.ts");
|
await import("./setup.ts");
|
||||||
sentry?.captureMessage("Server started", "info");
|
|
||||||
|
|
||||||
const serverLogger = getLogger("server");
|
|
||||||
|
|
||||||
for (const [worker, fn] of Object.entries(workers)) {
|
for (const [worker, fn] of Object.entries(workers)) {
|
||||||
serverLogger.info`Starting ${worker} Worker...`;
|
serverLogger.info`Starting ${worker} Worker...`;
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@versia-server/config": "workspace:*",
|
"@versia-server/config": "workspace:*",
|
||||||
"@versia-server/kit": "workspace:*",
|
"@versia-server/kit": "workspace:*",
|
||||||
"chalk": "catalog:",
|
"@versia-server/logging": "workspace:*",
|
||||||
"@logtape/logtape": "catalog:"
|
"chalk": "catalog:"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,12 @@
|
||||||
import { getLogger } from "@logtape/logtape";
|
|
||||||
import { config } from "@versia-server/config";
|
import { config } from "@versia-server/config";
|
||||||
import { Note, setupDatabase } from "@versia-server/kit/db";
|
import { Note, setupDatabase } from "@versia-server/kit/db";
|
||||||
import { connection } from "@versia-server/kit/redis";
|
import { connection } from "@versia-server/kit/redis";
|
||||||
|
import { serverLogger } from "@versia-server/logging";
|
||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
import { configureLoggers } from "@/loggers";
|
|
||||||
import { searchManager } from "../../classes/search/search-manager.ts";
|
import { searchManager } from "../../classes/search/search-manager.ts";
|
||||||
|
|
||||||
const timeAtStart = performance.now();
|
const timeAtStart = performance.now();
|
||||||
|
|
||||||
await configureLoggers();
|
|
||||||
|
|
||||||
const serverLogger = getLogger("server");
|
|
||||||
|
|
||||||
console.info(`
|
console.info(`
|
||||||
██╗ ██╗███████╗██████╗ ███████╗██╗ █████╗
|
██╗ ██╗███████╗██████╗ ███████╗██╗ █████╗
|
||||||
██║ ██║██╔════╝██╔══██╗██╔════╝██║██╔══██╗
|
██║ ██║██╔════╝██╔══██╗██╔════╝██║██╔══██╗
|
||||||
|
|
|
||||||
144
utils/loggers.ts
144
utils/loggers.ts
|
|
@ -1,144 +0,0 @@
|
||||||
import { mkdir } from "node:fs/promises";
|
|
||||||
import { dirname } from "node:path";
|
|
||||||
import { getRotatingFileSink } from "@logtape/file";
|
|
||||||
import {
|
|
||||||
configure,
|
|
||||||
getConsoleSink,
|
|
||||||
getLevelFilter,
|
|
||||||
type LogLevel,
|
|
||||||
type LogRecord,
|
|
||||||
} from "@logtape/logtape";
|
|
||||||
import { config } from "@versia-server/config";
|
|
||||||
import chalk from "chalk";
|
|
||||||
|
|
||||||
// config.logging.log_file_path is a path to a file, create the directory if it doesn't exist
|
|
||||||
await mkdir(dirname(config.logging.log_file_path), { recursive: true });
|
|
||||||
|
|
||||||
const levelAbbreviations: Record<LogLevel, string> = {
|
|
||||||
debug: "DBG",
|
|
||||||
info: "INF",
|
|
||||||
warning: "WRN",
|
|
||||||
error: "ERR",
|
|
||||||
fatal: "FTL",
|
|
||||||
trace: "TRC",
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The styles for the log level in the console.
|
|
||||||
*/
|
|
||||||
const logLevelStyles: Record<LogLevel, (text: string) => string> = {
|
|
||||||
debug: chalk.white.bgGray,
|
|
||||||
info: chalk.black.bgWhite,
|
|
||||||
warning: chalk.black.bgYellow,
|
|
||||||
error: chalk.white.bgRed,
|
|
||||||
fatal: chalk.white.bgRedBright,
|
|
||||||
trace: chalk.white.bgBlue,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The default console formatter.
|
|
||||||
*
|
|
||||||
* @param record The log record to format.
|
|
||||||
* @returns The formatted log record, as an array of arguments for
|
|
||||||
* {@link console.log}.
|
|
||||||
*/
|
|
||||||
export function defaultConsoleFormatter(record: LogRecord): string[] {
|
|
||||||
const msg = record.message.join("");
|
|
||||||
const date = new Date(record.timestamp);
|
|
||||||
const time = `${date.getUTCHours().toString().padStart(2, "0")}:${date
|
|
||||||
.getUTCMinutes()
|
|
||||||
.toString()
|
|
||||||
.padStart(
|
|
||||||
2,
|
|
||||||
"0",
|
|
||||||
)}:${date.getUTCSeconds().toString().padStart(2, "0")}.${date
|
|
||||||
.getUTCMilliseconds()
|
|
||||||
.toString()
|
|
||||||
.padStart(3, "0")}`;
|
|
||||||
|
|
||||||
const formattedTime = chalk.gray(time);
|
|
||||||
const formattedLevel = logLevelStyles[record.level](
|
|
||||||
levelAbbreviations[record.level],
|
|
||||||
);
|
|
||||||
const formattedCategory = chalk.gray(record.category.join("\xb7"));
|
|
||||||
const formattedMsg = chalk.reset(msg);
|
|
||||||
|
|
||||||
return [
|
|
||||||
`${formattedTime} ${formattedLevel} ${formattedCategory} ${formattedMsg}`,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
export const configureLoggers = (silent = false): Promise<void> =>
|
|
||||||
configure({
|
|
||||||
reset: true,
|
|
||||||
sinks: {
|
|
||||||
console: getConsoleSink({
|
|
||||||
formatter: defaultConsoleFormatter,
|
|
||||||
}),
|
|
||||||
file: getRotatingFileSink(config.logging.log_file_path, {
|
|
||||||
maxFiles: 10,
|
|
||||||
maxSize: 10 * 1024 * 1024,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
filters: {
|
|
||||||
configFilter: silent
|
|
||||||
? getLevelFilter(null)
|
|
||||||
: getLevelFilter(config.logging.log_level),
|
|
||||||
},
|
|
||||||
loggers: [
|
|
||||||
{
|
|
||||||
category: "server",
|
|
||||||
sinks: ["console", "file"],
|
|
||||||
filters: ["configFilter"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
category: ["federation", "inbox"],
|
|
||||||
sinks: ["console", "file"],
|
|
||||||
filters: ["configFilter"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
category: ["federation", "delivery"],
|
|
||||||
sinks: ["console", "file"],
|
|
||||||
filters: ["configFilter"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
category: ["federation", "bridge"],
|
|
||||||
sinks: ["console", "file"],
|
|
||||||
filters: ["configFilter"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
category: ["federation", "resolvers"],
|
|
||||||
sinks: ["console", "file"],
|
|
||||||
filters: ["configFilter"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
category: ["federation", "messaging"],
|
|
||||||
sinks: ["console", "file"],
|
|
||||||
filters: ["configFilter"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
category: "database",
|
|
||||||
sinks: ["console", "file"],
|
|
||||||
filters: ["configFilter"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
category: "webfinger",
|
|
||||||
sinks: ["console", "file"],
|
|
||||||
filters: ["configFilter"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
category: "sonic",
|
|
||||||
sinks: ["console", "file"],
|
|
||||||
filters: ["configFilter"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
category: ["logtape", "meta"],
|
|
||||||
lowestLevel: "error",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
category: "plugin",
|
|
||||||
sinks: ["console", "file"],
|
|
||||||
filters: ["configFilter"],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
import * as Sentry from "@sentry/bun";
|
|
||||||
import { config } from "@versia-server/config";
|
|
||||||
import { env } from "bun";
|
|
||||||
import pkg from "~/package.json" with { type: "json" };
|
|
||||||
|
|
||||||
const sentryInstance =
|
|
||||||
config.logging.sentry &&
|
|
||||||
Sentry.init({
|
|
||||||
dsn: config.logging.sentry.dsn.origin,
|
|
||||||
debug: config.logging.sentry.debug,
|
|
||||||
sampleRate: config.logging.sentry.sample_rate,
|
|
||||||
maxBreadcrumbs: config.logging.sentry.max_breadcrumbs,
|
|
||||||
tracesSampleRate: config.logging.sentry.traces_sample_rate,
|
|
||||||
environment: config.logging.sentry.environment,
|
|
||||||
tracePropagationTargets:
|
|
||||||
config.logging.sentry.trace_propagation_targets,
|
|
||||||
release: env.GIT_COMMIT
|
|
||||||
? `${pkg.version}-${env.GIT_COMMIT}`
|
|
||||||
: pkg.version,
|
|
||||||
integrations: [Sentry.extraErrorDataIntegration()],
|
|
||||||
});
|
|
||||||
|
|
||||||
export const sentry = sentryInstance || undefined;
|
|
||||||
|
|
@ -24,9 +24,7 @@ export const createServer = (
|
||||||
async fetch(req, server): Promise<Response> {
|
async fetch(req, server): Promise<Response> {
|
||||||
const output = await app.fetch(req, { ip: server.requestIP(req) });
|
const output = await app.fetch(req, { ip: server.requestIP(req) });
|
||||||
|
|
||||||
if (config.logging.types.responses) {
|
await debugResponse(output.clone());
|
||||||
await debugResponse(output.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue