Skip to content

Commit

Permalink
Merge pull request #47 from sima-land/38-bun-deno-support
Browse files Browse the repository at this point in the history
Шаг 9 #38
  • Loading branch information
krutoo authored Jun 5, 2023
2 parents 654aa4a + 318f842 commit d9fd499
Show file tree
Hide file tree
Showing 16 changed files with 527 additions and 356 deletions.
680 changes: 429 additions & 251 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@
"dependencies": {
"@humanwhocodes/env": "^2.2.2",
"@opentelemetry/api": "^1.4.1",
"@opentelemetry/exporter-jaeger": "^1.12.0",
"@opentelemetry/exporter-prometheus": "^0.38.0",
"@opentelemetry/exporter-trace-otlp-http": "^0.39.1",
"@opentelemetry/propagator-jaeger": "^1.12.0",
"@opentelemetry/resources": "^1.12.0",
"@opentelemetry/sdk-metrics": "^1.12.0",
Expand Down
10 changes: 5 additions & 5 deletions src/error-tracking/__test__/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { SentryError, SentryBreadcrumb } from '..';
import { DetailedError, Breadcrumb } from '..';

describe('SentryError', () => {
describe('DetailedError', () => {
it('name should be just "Error"', () => {
expect(new SentryError('hello, world!').name).toBe('Error');
expect(new DetailedError('hello, world!').name).toBe('Error');
});
});

describe('SentryBreadcrumb', () => {
describe('Breadcrumb', () => {
it('name should be just "Error"', () => {
expect(new SentryBreadcrumb({ message: 'some text' }).data).toEqual({ message: 'some text' });
expect(new Breadcrumb({ message: 'some text' }).data).toEqual({ message: 'some text' });
});
});
22 changes: 9 additions & 13 deletions src/error-tracking/index.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,33 @@
import { SentryErrorData, SentryBreadcrumbData } from './types';
import { ErrorDetails, BreadcrumbDetails } from './types';

/**
* Ошибка с данными для Sentry.
* @todo Этот класс должен называться либо SentryReadyError либо в названии вообще не должен фигурировать Sentry.
* Ошибка с данными.
*/
export class SentryError extends Error {
data: SentryErrorData;
export class DetailedError extends Error {
data: ErrorDetails;

/**
* @param message Сообщение.
* @param data Данные.
*/
constructor(message: string, data: SentryErrorData = {}) {
constructor(message?: string, data: ErrorDetails = {}) {
super(message);
this.data = data;
}
}

/**
* Хлебная крошка для Sentry.
* @todo Этот класс должен называться либо SentryReadyBreadcrumb либо в названии вообще не должен фигурировать Sentry.
* Хлебная крошка.
*/
export class SentryBreadcrumb {
export class Breadcrumb {
type: string;
data: SentryBreadcrumbData;
data: BreadcrumbDetails;

/**
* @param data Данные.
*/
constructor(data: SentryBreadcrumbData) {
constructor(data: BreadcrumbDetails) {
this.type = 'breadcrumb';
this.data = data;
}
}

// @todo переименовать error-tracking в events и добавить сюда остальные классы ошибок и событий?
8 changes: 4 additions & 4 deletions src/error-tracking/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ export interface ContextData {
}

/**
* Данные ошибки для Sentry.
* Детали ошибки.
*/
export interface SentryErrorData {
export interface ErrorDetails {
level?: SeverityLevel;

context?: ContextData | ContextData[];
Expand All @@ -20,6 +20,6 @@ export interface SentryErrorData {
}

/**
* Данные хлебной крошки для Sentry.
* Детали хлебной крошки.
*/
export type SentryBreadcrumbData = Breadcrumb;
export type BreadcrumbDetails = Breadcrumb;
5 changes: 3 additions & 2 deletions src/http-server/types.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import type { Request, Response, NextFunction } from 'express';

// @todo переименовать в HandlerContext
export interface ResponseContext {
export interface HandlerContext {
req: Request;
res: Response;
next: NextFunction;
}

// @todo перенести в пресеты?
export interface PageAssets {
js: string;
css: string;
Expand All @@ -24,6 +24,7 @@ export interface PageTemplate {
(data: PageTemplateData): string;
}

// @todo перенести в пресеты
export interface ConventionalJson {
markup: string;
bundle_js: string;
Expand Down
6 changes: 3 additions & 3 deletions src/log/handler/sentry.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { LogHandler } from '../types';
import type { Hub } from '@sentry/types';
import { SentryBreadcrumb, SentryError } from '../../error-tracking';
import { Breadcrumb, DetailedError } from '../../error-tracking';

/**
* Возвращает новый handler для logger'а для отправки событий в Sentry.
Expand All @@ -20,7 +20,7 @@ export function createSentryHandler(hubInit: Hub | (() => Hub)): LogHandler {
if (event.type === 'error') {
const error = event.data;

if (error instanceof SentryError) {
if (error instanceof DetailedError) {
const { level, context, extra } = error.data;

hub.withScope(scope => {
Expand Down Expand Up @@ -48,7 +48,7 @@ export function createSentryHandler(hubInit: Hub | (() => Hub)): LogHandler {
}

// breadcrumb
if (event.data instanceof SentryBreadcrumb) {
if (event.data instanceof Breadcrumb) {
const breadcrumb = event.data.data;

hub.addBreadcrumb(breadcrumb);
Expand Down
2 changes: 1 addition & 1 deletion src/log/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { Logger, LogEvent, LogEventType, LogHandler } from './types';
export { Logger, LogEvent, LogLevel, LogHandler } from './types';
export { createLogger } from './logger';
4 changes: 2 additions & 2 deletions src/log/logger.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Logger, LogEvent, LogEventType, LogHandler } from './types';
import type { Logger, LogEvent, LogLevel, LogHandler } from './types';

/**
* Возвращает новый logger - объект для журналирования событий подобно console.
Expand All @@ -8,7 +8,7 @@ export function createLogger(): Logger {
const handlers: LogHandler[] = [];

// eslint-disable-next-line require-jsdoc, jsdoc/require-jsdoc
const createMethod = (type: LogEventType) => (data: any) => {
const createMethod = (type: LogLevel) => (data: any) => {
const event: LogEvent = { type, data };

for (const handler of handlers) {
Expand Down
4 changes: 2 additions & 2 deletions src/log/types.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
/**
* Тип события.
*/
export type LogEventType = 'error' | 'log' | 'info' | 'warn' | 'debug';
export type LogLevel = 'error' | 'log' | 'info' | 'warn' | 'debug';

/**
* Интерфейс события.
*/
export interface LogEvent {
type: LogEventType;
type: LogLevel;
data: unknown;
}

Expand Down
7 changes: 4 additions & 3 deletions src/preset/node/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { HttpStatus } from '../parts/utils';

/**
* Возвращает preset с зависимостями по умолчанию для работы в рамках ответа на http-запрос.
* @todo Возможно стоит переименовать в PresetPageHandler.
* @return Preset.
*/
export function PresetHandler(): Preset {
Expand Down Expand Up @@ -162,15 +163,15 @@ export function provideSpecificParams(resolve: Resolve): Record<string, unknown>

/**
* Возвращает express-handler, создающий дочернее di-приложение при запросе.
* @param appFactory Фабрика di-приложения запроса.
* @param getApp Должна вернуть di-приложения запроса.
* @return Обработчик.
*/
export function HandlerProvider(appFactory: () => Application) {
export function HandlerProvider(getApp: () => Application) {
return function provider(resolve: Resolve): Handler {
const parent = resolve(CURRENT_APP);

return function handler(req, res, next) {
const app = appFactory();
const app = getApp();

app.attach(parent);
app.bind(KnownToken.Http.Handler.context).toValue({ req, res, next });
Expand Down
78 changes: 44 additions & 34 deletions src/preset/node/index.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,50 @@
/* eslint-disable require-jsdoc, jsdoc/require-jsdoc */
import path from 'path';
import type { Logger, LogHandler } from '../../log/types';
import type { Tracer } from '@opentelemetry/api';
import { Resolve, Preset, createPreset } from '../../di';
import {
BasicTracerProvider,
BatchSpanProcessor,
SpanExporter,
} from '@opentelemetry/sdk-trace-base';
import { KnownToken } from '../../tokens';
import { BridgeServerSide, SsrBridge } from '../../utils/ssr';
import { ConfigSource, createConfigSource } from '../../config';
import { createLogger } from '../../log';
import { createPinoHandler } from '../../log/handler/pino';
import { createSentryHandler } from '../../log/handler/sentry';
import { logMiddleware } from '../../http-server/middleware/log';
import { tracingMiddleware } from '../../http-server/middleware/tracing';
import {
renderMetricsMiddleware,
responseMetricsMiddleware,
renderMetricsMiddleware,
} from '../../http-server/middleware/metrics';
import { createDefaultMetrics } from '../../metrics/node';
import { JaegerExporter } from '@opentelemetry/exporter-jaeger';
import { HttpApiHostPool } from '../parts/utils';
import { KnownToken } from '../../tokens';
import { logMiddleware } from '../../http-server/middleware/log';
import { provideBaseConfig } from '../parts/providers';
import { Resolve, Preset, createPreset } from '../../di';
import { StrictMap, KnownHttpApiKey } from '../parts/types';
import { tracingMiddleware } from '../../http-server/middleware/tracing';

// nodejs specific packages
import os from 'node:os';
import path from 'node:path';

// nodejs libraries (not isomorphic)
import { config as applyDotenv } from 'dotenv';
import { create } from 'middleware-axios';
import Express, { Application, Handler } from 'express';
import { init, Handlers, getCurrentHub } from '@sentry/node';
import * as PromClient from 'prom-client';
import Express, { Application, Handler } from 'express';
import pino from 'pino';
import PinoPretty from 'pino-pretty';

// opentelemetry
import type { Tracer } from '@opentelemetry/api';
import {
BasicTracerProvider,
BatchSpanProcessor,
SpanExporter,
} from '@opentelemetry/sdk-trace-base';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { JaegerPropagator } from '@opentelemetry/propagator-jaeger';
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
import { Resource } from '@opentelemetry/resources';
import { JaegerPropagator } from '@opentelemetry/propagator-jaeger';
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';
import { getConventionalResource } from '../../tracing';
import { hostname } from 'os';
import { BridgeServerSide, SsrBridge } from '../../utils/ssr';
import { StrictMap, KnownHttpApiKey } from '../parts/types';
import { HttpApiHostPool } from '../parts/utils';
import { provideBaseConfig } from '../parts/providers';
import pino from 'pino';
import PinoPretty from 'pino-pretty';
import { config as applyDotenv } from 'dotenv';
import { healthCheck } from '../../http-server/handler/health-check';
import { composeMiddleware } from '../../http-server/utils';
import * as PromClient from 'prom-client';
import { createDefaultMetrics } from '../../metrics/node';

/**
* Возвращает preset с зависимостями по умолчанию для frontend-микросервисов на Node.js.
Expand Down Expand Up @@ -67,6 +73,7 @@ export function PresetNode(): Preset {

// http server
[KnownToken.Http.Server.factory, () => Express],
[KnownToken.Http.Server.Handler.healthCheck, () => healthCheck()],
[KnownToken.Http.Server.Middleware.request, () => Handlers.requestHandler()],
[KnownToken.Http.Server.Middleware.log, provideHttpServerLogMiddleware],
[KnownToken.Http.Server.Middleware.metrics, provideHttpServerMetricsMiddleware],
Expand Down Expand Up @@ -147,9 +154,11 @@ export function provideTracer(resolve: Resolve): Tracer {
export function provideSpanExporter(resolve: Resolve): SpanExporter {
const source = resolve(KnownToken.Config.source);

return new JaegerExporter({
host: source.require('JAEGER_AGENT_HOST'),
port: parseInt(source.require('JAEGER_AGENT_PORT')) || undefined,
const host = source.require('JAEGER_AGENT_HOST');
const port = source.require('JAEGER_AGENT_PORT');

return new OTLPTraceExporter({
url: port ? `${host}:${port}` : host,
});
}

Expand All @@ -168,11 +177,12 @@ export function provideTracerProvider(resolve: Resolve): BasicTracerProvider {
export function provideTracerProviderResource(resolve: Resolve): Resource {
const config = resolve(KnownToken.Config.base);

return getConventionalResource(config).merge(
new Resource({
[SemanticResourceAttributes.HOST_NAME]: hostname(),
}),
);
return new Resource({
[SemanticResourceAttributes.HOST_NAME]: os.hostname(),
[SemanticResourceAttributes.SERVICE_NAME]: config.appName,
[SemanticResourceAttributes.SERVICE_VERSION]: config.appVersion,
[SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: config.env,
});
}

export function provideHttpServerLogMiddleware(resolve: Resolve): Handler {
Expand Down
Loading

0 comments on commit d9fd499

Please sign in to comment.