mirror of
https://github.com/Unleash/unleash.git
synced 2025-04-15 01:16:22 +02:00
feat: resolve useragent source and add as source label to metrics (#7883)
This commit is contained in:
parent
183a9fc737
commit
cf83043d8a
@ -30,6 +30,7 @@ type MetricEvent =
|
||||
type RequestOriginEventPayload = {
|
||||
type: 'UI' | 'API';
|
||||
method: Request['method'];
|
||||
source?: string;
|
||||
};
|
||||
|
||||
type MetricEventPayloads = {
|
||||
|
@ -350,7 +350,7 @@ export default class MetricsMonitor {
|
||||
const requestOriginCounter = createCounter({
|
||||
name: 'request_origin_counter',
|
||||
help: 'Number of authenticated requests, including origin information.',
|
||||
labelNames: ['type', 'method'],
|
||||
labelNames: ['type', 'method', 'source'],
|
||||
});
|
||||
|
||||
const resourceLimit = createGauge({
|
||||
@ -715,9 +715,9 @@ export default class MetricsMonitor {
|
||||
events.onMetricEvent(
|
||||
eventBus,
|
||||
events.REQUEST_ORIGIN,
|
||||
({ type, method }) => {
|
||||
({ type, method, source }) => {
|
||||
if (flagResolver.isEnabled('originMiddleware')) {
|
||||
requestOriginCounter.increment({ type, method });
|
||||
requestOriginCounter.increment({ type, method, source });
|
||||
}
|
||||
},
|
||||
);
|
||||
|
29
src/lib/middleware/integration-headers.test.ts
Normal file
29
src/lib/middleware/integration-headers.test.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { determineIntegrationSource } from './integration-headers';
|
||||
|
||||
test('resolves known user agents to source labels', () => {
|
||||
expect(determineIntegrationSource('axios/0.27.2')).toBe('Axios');
|
||||
expect(determineIntegrationSource('axios/1.4.0')).toBe('Axios');
|
||||
expect(determineIntegrationSource('curl/8.6.0')).toBe('Curl');
|
||||
expect(determineIntegrationSource('node-fetch/1.0.0')).toBe('Node');
|
||||
expect(determineIntegrationSource('node')).toBe('Node');
|
||||
expect(determineIntegrationSource('python-requests/2.31.0')).toBe('Python');
|
||||
expect(determineIntegrationSource('Terraform-Provider-Unleash/1.1.1')).toBe(
|
||||
'TerraformUnleash',
|
||||
);
|
||||
expect(determineIntegrationSource('Jira-Cloud-Unleash')).toBe(
|
||||
'JiraCloudUnleash',
|
||||
);
|
||||
expect(determineIntegrationSource('OpenAPI-Generator/1.0.0/go')).toBe(
|
||||
'OpenAPIGO',
|
||||
);
|
||||
expect(
|
||||
determineIntegrationSource('Apache-HttpClient/4.5.13 (Java/11.0.22)'),
|
||||
).toBe('Java');
|
||||
expect(determineIntegrationSource('Go-http-client/1.1')).toBe('Go');
|
||||
expect(
|
||||
determineIntegrationSource(
|
||||
'rest-client/2.0.2 (linux-gnu x86_64) ruby/2.1.7p400',
|
||||
),
|
||||
).toBe('RestClientRuby');
|
||||
expect(determineIntegrationSource('No-http-client')).toBe('Other');
|
||||
});
|
34
src/lib/middleware/integration-headers.ts
Normal file
34
src/lib/middleware/integration-headers.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import type { Request } from 'express';
|
||||
|
||||
const ORIGIN = 'origin';
|
||||
const httpMatcher = /^https?:\/\//;
|
||||
const userAgentMatches = [
|
||||
{ label: 'Axios', matcher: /^axios/ },
|
||||
{ label: 'Curl', matcher: /^curl/ },
|
||||
{ label: 'Go', matcher: /^Go-http-client/ },
|
||||
{ label: 'Python', matcher: /^python-requests/ },
|
||||
{ label: 'Node', matcher: /^node/ },
|
||||
{ label: 'Java', matcher: /^Apache-HttpClient.*Java/ },
|
||||
{ label: 'JiraCloudUnleash', matcher: /^Jira-Cloud-Unleash/ },
|
||||
{ label: 'TerraformUnleash', matcher: /^Terraform-Provider-Unleash/ },
|
||||
{ label: 'OpenAPIGO', matcher: /^OpenAPI-Generator\/.*\/go/ },
|
||||
{ label: 'RestClientRuby', matcher: /^rest-client\/.*ruby/ },
|
||||
];
|
||||
|
||||
export const getFilteredOrigin = (request: Request): string | undefined => {
|
||||
const origin = request.headers[ORIGIN];
|
||||
if (origin && httpMatcher.test(origin)) {
|
||||
return origin;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export const determineIntegrationSource = (
|
||||
userAgent: string,
|
||||
): string | undefined => {
|
||||
return (
|
||||
userAgentMatches.find((candidate) => candidate.matcher.test(userAgent))
|
||||
?.label ?? 'Other'
|
||||
);
|
||||
};
|
@ -69,6 +69,7 @@ describe('originMiddleware', () => {
|
||||
expect(eventBus.emit).toHaveBeenCalledWith(REQUEST_ORIGIN, {
|
||||
type: 'API',
|
||||
method: req.method,
|
||||
source: 'Other',
|
||||
});
|
||||
});
|
||||
|
||||
@ -83,6 +84,7 @@ describe('originMiddleware', () => {
|
||||
expect(loggerMock.info).toHaveBeenCalledWith('API request', {
|
||||
method: req.method,
|
||||
userAgent: TEST_USER_AGENT,
|
||||
origin: undefined,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,6 +1,10 @@
|
||||
import type { Request, Response, NextFunction } from 'express';
|
||||
import type { IUnleashConfig } from '../types';
|
||||
import { REQUEST_ORIGIN, emitMetricEvent } from '../metric-events';
|
||||
import {
|
||||
determineIntegrationSource,
|
||||
getFilteredOrigin,
|
||||
} from './integration-headers';
|
||||
|
||||
export const originMiddleware = ({
|
||||
getLogger,
|
||||
@ -23,13 +27,19 @@ export const originMiddleware = ({
|
||||
method: req.method,
|
||||
});
|
||||
} else {
|
||||
const userAgent = req.headers['user-agent'];
|
||||
const uaLabel = userAgent
|
||||
? determineIntegrationSource(userAgent)
|
||||
: 'Other';
|
||||
logger.info('API request', {
|
||||
method: req.method,
|
||||
userAgent: req.headers['user-agent'],
|
||||
origin: getFilteredOrigin(req),
|
||||
});
|
||||
emitMetricEvent(eventBus, REQUEST_ORIGIN, {
|
||||
type: 'API',
|
||||
method: req.method,
|
||||
source: uaLabel,
|
||||
});
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user