Skip to content

Commit

Permalink
Merge pull request #112 from sima-land/38-examples-bun
Browse files Browse the repository at this point in the history
 Шаг 65 #38
  • Loading branch information
krutoo committed Mar 11, 2024
2 parents 2f9530e + 35eacea commit 33e87cf
Show file tree
Hide file tree
Showing 17 changed files with 221 additions and 237 deletions.
2 changes: 1 addition & 1 deletion src/preset/bun-handler/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
provideReduxMiddlewareSaga,
} from '../isomorphic/providers';
import { providePageRender } from '../node-handler/providers';
import { SpecificExtras } from '../node-handler/utils';
import { SpecificExtras } from '../server/utils/specific-extras';
import { HandlerProviders } from './providers';

/**
Expand Down
2 changes: 1 addition & 1 deletion src/preset/bun-handler/providers/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import { renderToString } from 'react-dom/server';
import { Resolve } from '../../../di';
import { KnownToken } from '../../../tokens';
import { HelmetContext, RegularHelmet } from '../../node-handler/utils';
import {
CookieStore,
Middleware,
Expand All @@ -21,6 +20,7 @@ import { getFetchLogging } from '../../isomorphic/utils/get-fetch-logging';
import { FetchLogging } from '../../isomorphic/utils/fetch-logging';
import { PageAssets } from '../../isomorphic/types';
import { PAGE_HANDLER_EVENT_TYPE } from '../../server/constants';
import { HelmetContext, RegularHelmet } from '../../server/utils/regular-helmet';
import { getPageResponseFormat } from '../../server/utils/get-page-response-format';
import { getForwardedHeaders } from '../../server/utils/get-forwarded-headers';

Expand Down
2 changes: 1 addition & 1 deletion src/preset/node-handler/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
provideFetchLogHandler,
provideCookieStore,
} from './providers';
import { SpecificExtras } from './utils';
import { SpecificExtras } from '../server/utils/specific-extras';

/**
* Возвращает preset с зависимостями по умолчанию для работы в рамках ответа на http-запрос.
Expand Down
9 changes: 4 additions & 5 deletions src/preset/node-handler/providers/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,8 @@ import {
} from '../../../http';
import type { Resolve } from '../../../di';
import { KnownToken } from '../../../tokens';
import {
getForwardedHeaders as getForwardedHeadersExpress,
axiosTracingMiddleware,
} from '../../node/utils/http-client';
import { getForwardedHeaders as getForwardedHeadersExpress } from '../../node/utils/get-forwarded-headers';
import { axiosTracingMiddleware } from '../../node/utils/axios-tracing-middleware';
import type { Middleware as AxiosMiddleware } from 'middleware-axios';
import { AxiosLogging } from '../../isomorphic/utils/axios-logging';
import { FetchLogging } from '../../isomorphic/utils/fetch-logging';
Expand All @@ -24,9 +22,10 @@ import { LogMiddlewareHandlerInit, cookieMiddleware, logMiddleware } from '../..
import { PAGE_HANDLER_EVENT_TYPE } from '../../server/constants';
import type { ConventionalJson } from '../../isomorphic/types';
import { Fragment } from 'react';
import { HelmetContext, RegularHelmet, getPageResponseFormat } from '../utils';
import { getPageResponseFormat } from '../../node/utils/get-page-response-format';
import { renderToString } from 'react-dom/server';
import { getFetchTracing } from '../../server/utils/get-fetch-tracing';
import { HelmetContext, RegularHelmet } from '../../server/utils/regular-helmet';

/**
* Провайдер главной функции обработчика входящего http-запроса.
Expand Down
48 changes: 13 additions & 35 deletions src/preset/node/providers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { Resolve } from '../../../di';
import { KnownHttpApiKey } from '../../isomorphic/types';
import { toMilliseconds } from '../../../utils';
import { PAGE_HANDLER_EVENT_TYPE } from '../../server/constants';
import { getClientIp } from '../utils/http-server';
import { getClientIp } from '../utils/get-client-ip';

// Node.js specific packages
import os from 'node:os';
Expand All @@ -36,6 +36,7 @@ import { JaegerPropagator } from '@opentelemetry/propagator-jaeger';
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
import { Resource } from '@opentelemetry/resources';
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';
import { getHandlerMetrics, LABEL_NAMES } from '../../server/utils/get-handler-metrics';

/**
* Провайдер источника конфигурации.
Expand Down Expand Up @@ -236,31 +237,7 @@ export function provideExpressLogMiddleware(resolve: Resolve): Handler {
*/
export function provideExpressMetricsMiddleware(resolve: Resolve): Handler {
const config = resolve(KnownToken.Config.base);

const ConventionalLabels = {
HTTP_RESPONSE: ['version', 'route', 'code', 'method'],
SSR: ['version', 'route', 'method'],
} as const;

const requestCount = new PromClient.Counter({
name: 'http_request_count',
help: 'Incoming HTTP request count',
labelNames: ConventionalLabels.HTTP_RESPONSE,
});

const responseDuration = new PromClient.Histogram({
name: 'http_response_duration_ms',
help: 'Duration of incoming HTTP requests in ms',
labelNames: ConventionalLabels.HTTP_RESPONSE,
buckets: [30, 100, 200, 500, 1000, 2500, 5000, 10000],
});

const renderDuration = new PromClient.Histogram({
name: 'render_duration_ms',
help: 'Duration of SSR ms',
labelNames: ConventionalLabels.SSR,
buckets: [0.1, 15, 50, 100, 250, 500, 800, 1500],
});
const { requestCount, renderDuration, responseDuration } = getHandlerMetrics();

/**
* Функция формирования labels.
Expand All @@ -271,13 +248,21 @@ export function provideExpressMetricsMiddleware(resolve: Resolve): Handler {
const getLabels = (
req: Request,
res: Response,
): Record<(typeof ConventionalLabels.HTTP_RESPONSE)[number], string | number> => ({
): 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: 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();

Expand All @@ -289,14 +274,7 @@ export function provideExpressMetricsMiddleware(resolve: Resolve): Handler {
res.once(PAGE_HANDLER_EVENT_TYPE.renderFinish, () => {
const renderFinish = process.hrtime.bigint();

renderDuration.observe(
{
version: config.appVersion,
method: req.method,
route: req.baseUrl + req.path,
},
toMilliseconds(renderFinish - renderStart),
);
renderDuration.observe(getRenderLabels(req), toMilliseconds(renderFinish - renderStart));
});
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { Context } from '@opentelemetry/api';
import { SemanticAttributes } from '@opentelemetry/semantic-conventions';
import { Span, Tracer } from '@opentelemetry/sdk-trace-base';
import { axiosTracingMiddleware, getRequestInfo, getForwardedHeaders } from '..';
import { BaseConfig } from '../../../../../config';
import express from 'express';
import { axiosTracingMiddleware, getRequestInfo } from '../axios-tracing-middleware';

describe('axiosTracingMiddleware', () => {
describe('getAxiosTracing', () => {
it('should handle success response', async () => {
let currentSpan: Span = null as any;

Expand Down Expand Up @@ -143,67 +141,3 @@ describe('getRequestInfo', () => {
}
});
});

describe('getRequestHeaders', () => {
it('should return headers', () => {
const config: BaseConfig = {
appName: 'foo',
appVersion: '0.0.1',
env: 'test',
};

const request: express.Request = {
socket: {
remoteAddress: '127.0.0.1',
},
headers: {
cookie: 'userid=12345',
'simaland-a': 'aaa',
'simaland-b': 'bbb',
},
get(key: string) {
return this.headers[key];
},
header(key: string) {
return this.headers[key];
},
} as any;

const result = getForwardedHeaders(config, request);

expect(result).toEqual({
'X-Client-Ip': '127.0.0.1',
'User-Agent': `simaland-foo/0.0.1`,
Cookie: 'userid=12345',
'simaland-a': 'aaa',
'simaland-b': 'bbb',
});
});

it('should return headers when lot of data is undefined', () => {
const config: BaseConfig = {
appName: 'foo',
appVersion: '0.0.1',
env: 'test',
};

const request: express.Request = {
socket: {
remoteAddress: undefined,
},
headers: {},
get(key: string) {
return this.headers[key];
},
header(key: string) {
return this.headers[key];
},
} as any;

const result = getForwardedHeaders(config, request);

expect(result).toEqual({
'User-Agent': `simaland-foo/0.0.1`,
});
});
});
67 changes: 67 additions & 0 deletions src/preset/node/utils/__test__/get-forwarded-headers.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import type express from 'express';
import type { BaseConfig } from '../../../../config';
import { getForwardedHeaders } from '../get-forwarded-headers';

describe('getForwardedHeaders', () => {
it('should return headers', () => {
const config: BaseConfig = {
appName: 'foo',
appVersion: '0.0.1',
env: 'test',
};

const request: express.Request = {
socket: {
remoteAddress: '127.0.0.1',
},
headers: {
cookie: 'userid=12345',
'simaland-a': 'aaa',
'simaland-b': 'bbb',
},
get(key: string) {
return this.headers[key];
},
header(key: string) {
return this.headers[key];
},
} as any;

const result = getForwardedHeaders(config, request);

expect(result).toEqual({
'X-Client-Ip': '127.0.0.1',
'User-Agent': `simaland-foo/0.0.1`,
Cookie: 'userid=12345',
'simaland-a': 'aaa',
'simaland-b': 'bbb',
});
});

it('should return headers when lot of data is undefined', () => {
const config: BaseConfig = {
appName: 'foo',
appVersion: '0.0.1',
env: 'test',
};

const request: express.Request = {
socket: {
remoteAddress: undefined,
},
headers: {},
get(key: string) {
return this.headers[key];
},
header(key: string) {
return this.headers[key];
},
} as any;

const result = getForwardedHeaders(config, request);

expect(result).toEqual({
'User-Agent': `simaland-foo/0.0.1`,
});
});
});
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import type { AxiosDefaults, AxiosRequestConfig } from 'axios';
import type { Middleware } from 'middleware-axios';
import type express from 'express';
import { Context, Tracer, SpanStatusCode } from '@opentelemetry/api';
import { SemanticAttributes } from '@opentelemetry/semantic-conventions';
import { BaseConfig } from '../../../../config';
import { getClientIp } from '../http-server';
import { displayUrl } from '../../../isomorphic/utils/display-url';
import { hideFirstId } from '../../../isomorphic/utils/hide-first-id';
import { displayUrl } from '../../isomorphic/utils/display-url';
import { hideFirstId } from '../../isomorphic/utils/hide-first-id';

/**
* Возвращает новый middleware для трассировки исходящих запросов.
Expand Down Expand Up @@ -80,43 +77,3 @@ export function getRequestInfo(
foundId,
};
}

/**
* Формирует заголовки для исходящих запросов с сервера по соглашению.
* @param config Конфиг.
* @param request Входящий запрос.
* @return Заголовки для исходящих запросов.
*/
export function getForwardedHeaders(
config: BaseConfig,
request: express.Request,
): Record<string, string> {
const result: Record<string, string> = {
'User-Agent': `simaland-${config.appName}/${config.appVersion}`,
};

const clientIp = getClientIp(request);
if (clientIp) {
result['X-Client-Ip'] = clientIp;
}

const cookie = request.header('cookie');
if (cookie) {
result.Cookie = cookie;
}

// добавляем специфичные заголовки
for (const key of Object.keys(request.headers)) {
const value = request.header(key);

if (
key.toLowerCase().startsWith('simaland-') &&
key.toLowerCase() !== 'simaland-params' &&
value
) {
result[key] = value;
}
}

return result;
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import type { Request } from 'express';
import type express from 'express';
import net from 'node:net';

/**
* Определяет IP входящего запроса.
* @param request Входящий запрос.
* @return IP.
*/
export function getClientIp(request: Request): string | undefined {
export function getClientIp(request: express.Request): string | undefined {
const headerValue =
request.header('x-client-ip') ||
request.header('x-forwarded-for') ||
Expand Down
Loading

0 comments on commit 33e87cf

Please sign in to comment.