-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #115 from sima-land/38-examples-bun
Шаг 68 #38
- Loading branch information
Showing
21 changed files
with
454 additions
and
423 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import path from 'node:path'; | ||
import { config as applyDotenv } from 'dotenv'; | ||
import { ConfigSource, createConfigSource } from '../../../config'; | ||
|
||
/** | ||
* Провайдер источника конфигурации. | ||
* @return Источник конфигурации. | ||
*/ | ||
export function provideConfigSource(): ConfigSource { | ||
const envName = process.env.NODE_ENV; | ||
|
||
// подключаем соответствующий среде файл со значениями по умолчанию | ||
if (envName) { | ||
applyDotenv({ path: path.resolve(process.cwd(), `./.env.${envName}`) }); | ||
} | ||
|
||
// @todo подключать .env, .env.local, .env.<envName>, .env.<envName>.local как в Vite/Bun | ||
|
||
return createConfigSource(process.env); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import type express from 'express'; | ||
import { Handlers } from '@sentry/node'; | ||
|
||
/** | ||
* Провайдер промежуточного слоя обработки ошибок в рамках ответ на http-запросы. | ||
* @return Промежуточный слой. | ||
*/ | ||
export function provideExpressErrorMiddleware(): express.ErrorRequestHandler { | ||
return Handlers.errorHandler(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import express from 'express'; | ||
|
||
/** | ||
* Провайдер фабрики http-серверов. | ||
* @return Фабрика. | ||
*/ | ||
export function provideExpressFactory() { | ||
return express; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import type express from 'express'; | ||
import type { Resolve } from '../../../di'; | ||
import type { ConventionalFluentInfo } from '../../../log/types'; | ||
import { KnownToken } from '../../../tokens'; | ||
import { getClientIp } from '../utils/get-client-ip'; | ||
import { toMilliseconds } from '../../../utils'; | ||
|
||
/** | ||
* Провайдер промежуточного слоя логирования входящих http-запросов. | ||
* @param resolve Функция для получения зависимости по токену. | ||
* @return Промежуточный слой. | ||
*/ | ||
export function provideExpressLogMiddleware(resolve: Resolve): express.Handler { | ||
const config = resolve(KnownToken.Config.base); | ||
const logger = resolve(KnownToken.logger); | ||
|
||
return (req, res, next) => { | ||
const start = process.hrtime.bigint(); | ||
const remoteIp = getClientIp(req) ?? ''; | ||
|
||
const startMsg: Omit<ConventionalFluentInfo, 'latency' | 'status'> & { type: string } = { | ||
type: 'http.request[incoming]', | ||
version: config.appVersion, | ||
route: req.originalUrl, | ||
method: req.method, | ||
remote_ip: remoteIp, | ||
}; | ||
|
||
logger.info(startMsg); | ||
|
||
res.once('finish', () => { | ||
const finish = process.hrtime.bigint(); | ||
|
||
const finishMsg: ConventionalFluentInfo & { type: string } = { | ||
type: 'http.response[outgoing]', | ||
version: config.appVersion, | ||
route: req.originalUrl, | ||
method: req.method, | ||
status: res.statusCode, | ||
remote_ip: remoteIp, | ||
latency: toMilliseconds(finish - start), | ||
}; | ||
|
||
logger.info(finishMsg); | ||
}); | ||
|
||
next(); | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import type express from 'express'; | ||
import type { Resolve } from '../../../di'; | ||
import { LABEL_NAMES, getHandlerMetrics } from '../../server/utils/get-handler-metrics'; | ||
import { KnownToken } from '../../../tokens'; | ||
import { PAGE_HANDLER_EVENT_TYPE } from '../../server'; | ||
import { toMilliseconds } from '../../../utils'; | ||
|
||
/** | ||
* Провайдер промежуточного слоя сбора метрик входящих http-запросов. | ||
* @param resolve Функция для получения зависимости по токену. | ||
* @return Промежуточный слой. | ||
*/ | ||
export function provideExpressMetricsMiddleware(resolve: Resolve): express.Handler { | ||
const config = resolve(KnownToken.Config.base); | ||
const { requestCount, renderDuration, responseDuration } = getHandlerMetrics(); | ||
|
||
/** | ||
* Функция формирования labels. | ||
* @param req Request. | ||
* @param res Response. | ||
* @return Labels. | ||
*/ | ||
const getLabels = ( | ||
req: express.Request, | ||
res: express.Response, | ||
): Record<(typeof LABEL_NAMES.httpResponse)[number], string | number> => ({ | ||
version: config.appVersion, | ||
route: req.baseUrl + req.path, | ||
code: res.statusCode, | ||
method: req.method, | ||
}); | ||
|
||
/** @inheritdoc */ | ||
const getRenderLabels = (request: express.Request) => | ||
({ | ||
version: config.appVersion, | ||
method: request.method, | ||
route: request.url, | ||
}) satisfies Record<(typeof LABEL_NAMES.pageRender)[number], string | number>; | ||
|
||
return (req, res, next) => { | ||
const responseStart = process.hrtime.bigint(); | ||
|
||
requestCount.inc(getLabels(req, res), 1); | ||
|
||
res.once(PAGE_HANDLER_EVENT_TYPE.renderStart, () => { | ||
const renderStart = process.hrtime.bigint(); | ||
|
||
res.once(PAGE_HANDLER_EVENT_TYPE.renderFinish, () => { | ||
const renderFinish = process.hrtime.bigint(); | ||
|
||
renderDuration.observe(getRenderLabels(req), toMilliseconds(renderFinish - renderStart)); | ||
}); | ||
}); | ||
|
||
res.once('finish', () => { | ||
const responseFinish = process.hrtime.bigint(); | ||
|
||
responseDuration.observe(getLabels(req, res), toMilliseconds(responseFinish - responseStart)); | ||
}); | ||
|
||
next(); | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import type express from 'express'; | ||
import { Handlers } from '@sentry/node'; | ||
|
||
/** | ||
* Провайдер промежуточного слоя учета входящих http-запросов. | ||
* @return Промежуточный слой. | ||
*/ | ||
export function provideExpressRequestMiddleware(): express.Handler { | ||
return Handlers.requestHandler(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import type express from 'express'; | ||
import type { Resolve } from '../../../di'; | ||
import { KnownToken } from '../../../tokens'; | ||
import { ROOT_CONTEXT, propagation, trace } from '@opentelemetry/api'; | ||
import { PAGE_HANDLER_EVENT_TYPE } from '../../server'; | ||
|
||
/** | ||
* Провайдер промежуточного слоя трассировки входящих http-запросов. | ||
* @param resolve Функция для получения зависимости по токену. | ||
* @return Промежуточный слой. | ||
*/ | ||
export function provideExpressTracingMiddleware(resolve: Resolve): express.Handler { | ||
const tracer = resolve(KnownToken.Tracing.tracer); | ||
|
||
/** | ||
* Возвращает набор стандартных атрибутов для спана. | ||
* @param req Входящий http-запрос. | ||
* @return Атрибуты. | ||
*/ | ||
const getConventionalRequestAttrs = ( | ||
req: express.Request, | ||
): Record<string, string | undefined> => { | ||
const result: Record<string, string | undefined> = { | ||
'request.path': req.originalUrl, | ||
}; | ||
|
||
for (const headerName in req.headers) { | ||
if (headerName.toLowerCase().startsWith('simaland-')) { | ||
result[headerName] = req.header(headerName); | ||
} | ||
} | ||
|
||
return result; | ||
}; | ||
|
||
return (req, res, next) => { | ||
const externalContext = propagation.extract(ROOT_CONTEXT, req.headers); | ||
const rootSpan = tracer.startSpan('response', undefined, externalContext); | ||
|
||
rootSpan.setAttributes(getConventionalRequestAttrs(req)); | ||
|
||
const rootContext = trace.setSpan(externalContext, rootSpan); | ||
|
||
res.locals.tracing = { | ||
rootSpan, | ||
rootContext, | ||
renderSpan: null, | ||
}; | ||
|
||
res.once(PAGE_HANDLER_EVENT_TYPE.renderStart, () => { | ||
res.locals.tracing.renderSpan = tracer.startSpan('render', undefined, rootContext); | ||
|
||
res.once(PAGE_HANDLER_EVENT_TYPE.renderFinish, () => { | ||
res.locals.tracing.renderSpan.end(); | ||
}); | ||
}); | ||
|
||
res.once('finish', () => { | ||
rootSpan.end(); | ||
}); | ||
|
||
next(); | ||
}; | ||
} |
Oops, something went wrong.