-
Notifications
You must be signed in to change notification settings - Fork 8.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[7.x] [core.logging] Add response logs to the KP logging system. (#87939
) (#90280)
- Loading branch information
1 parent
012d453
commit f9b2ad1
Showing
20 changed files
with
1,383 additions
and
66 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
101 changes: 101 additions & 0 deletions
101
packages/kbn-legacy-logging/src/utils/get_payload_size.test.ts
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,101 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0 and the Server Side Public License, v 1; you may not use this file except | ||
* in compliance with, at your election, the Elastic License 2.0 or the Server | ||
* Side Public License, v 1. | ||
*/ | ||
|
||
import mockFs from 'mock-fs'; | ||
import { createReadStream } from 'fs'; | ||
|
||
import { getResponsePayloadBytes } from './get_payload_size'; | ||
|
||
describe('getPayloadSize', () => { | ||
describe('handles Buffers', () => { | ||
test('with ascii characters', () => { | ||
const payload = 'heya'; | ||
const result = getResponsePayloadBytes(Buffer.from(payload)); | ||
expect(result).toBe(4); | ||
}); | ||
|
||
test('with special characters', () => { | ||
const payload = '¡hola!'; | ||
const result = getResponsePayloadBytes(Buffer.from(payload)); | ||
expect(result).toBe(7); | ||
}); | ||
}); | ||
|
||
describe('handles fs streams', () => { | ||
afterEach(() => mockFs.restore()); | ||
|
||
test('with ascii characters', async () => { | ||
mockFs({ 'test.txt': 'heya' }); | ||
const readStream = createReadStream('test.txt'); | ||
|
||
let data = ''; | ||
for await (const chunk of readStream) { | ||
data += chunk; | ||
} | ||
|
||
const result = getResponsePayloadBytes(readStream); | ||
expect(result).toBe(Buffer.byteLength(data)); | ||
}); | ||
|
||
test('with special characters', async () => { | ||
mockFs({ 'test.txt': '¡hola!' }); | ||
const readStream = createReadStream('test.txt'); | ||
|
||
let data = ''; | ||
for await (const chunk of readStream) { | ||
data += chunk; | ||
} | ||
|
||
const result = getResponsePayloadBytes(readStream); | ||
expect(result).toBe(Buffer.byteLength(data)); | ||
}); | ||
}); | ||
|
||
describe('handles plain responses', () => { | ||
test('when source is text', () => { | ||
const result = getResponsePayloadBytes('heya'); | ||
expect(result).toBe(4); | ||
}); | ||
|
||
test('when source contains special characters', () => { | ||
const result = getResponsePayloadBytes('¡hola!'); | ||
expect(result).toBe(7); | ||
}); | ||
|
||
test('when source is object', () => { | ||
const payload = { message: 'heya' }; | ||
const result = getResponsePayloadBytes(payload); | ||
expect(result).toBe(JSON.stringify(payload).length); | ||
}); | ||
}); | ||
|
||
describe('handles content-length header', () => { | ||
test('always provides content-length header if available', () => { | ||
const headers = { 'content-length': '123' }; | ||
const result = getResponsePayloadBytes('heya', headers); | ||
expect(result).toBe(123); | ||
}); | ||
|
||
test('uses first value when hapi header is an array', () => { | ||
const headers = { 'content-length': ['123', '456'] }; | ||
const result = getResponsePayloadBytes(null, headers); | ||
expect(result).toBe(123); | ||
}); | ||
|
||
test('returns undefined if length is NaN', () => { | ||
const headers = { 'content-length': 'oops' }; | ||
const result = getResponsePayloadBytes(null, headers); | ||
expect(result).toBeUndefined(); | ||
}); | ||
}); | ||
|
||
test('defaults to undefined', () => { | ||
const result = getResponsePayloadBytes(null); | ||
expect(result).toBeUndefined(); | ||
}); | ||
}); |
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 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0 and the Server Side Public License, v 1; you may not use this file except | ||
* in compliance with, at your election, the Elastic License 2.0 or the Server | ||
* Side Public License, v 1. | ||
*/ | ||
|
||
import type { ReadStream } from 'fs'; | ||
import type { ResponseObject } from '@hapi/hapi'; | ||
|
||
const isBuffer = (obj: unknown): obj is Buffer => Buffer.isBuffer(obj); | ||
const isObject = (obj: unknown): obj is Record<string, unknown> => | ||
typeof obj === 'object' && obj !== null; | ||
const isFsReadStream = (obj: unknown): obj is ReadStream => | ||
typeof obj === 'object' && obj !== null && 'bytesRead' in obj; | ||
const isString = (obj: unknown): obj is string => typeof obj === 'string'; | ||
|
||
/** | ||
* Attempts to determine the size (in bytes) of a hapi/good | ||
* responsePayload based on the payload type. Falls back to | ||
* `undefined` if the size cannot be determined. | ||
* | ||
* This is similar to the implementation in `core/server/http/logging`, | ||
* however it uses more duck typing as we do not have access to the | ||
* entire hapi request object like we do in the HttpServer. | ||
* | ||
* @param headers responseHeaders from hapi/good event | ||
* @param payload responsePayload from hapi/good event | ||
* | ||
* @internal | ||
*/ | ||
export function getResponsePayloadBytes( | ||
payload: ResponseObject['source'], | ||
headers: Record<string, any> = {} | ||
): number | undefined { | ||
const contentLength = headers['content-length']; | ||
if (contentLength) { | ||
const val = parseInt( | ||
// hapi response headers can be `string | string[]`, so we need to handle both cases | ||
Array.isArray(contentLength) ? String(contentLength) : contentLength, | ||
10 | ||
); | ||
return !isNaN(val) ? val : undefined; | ||
} | ||
|
||
if (isBuffer(payload)) { | ||
return payload.byteLength; | ||
} | ||
|
||
if (isFsReadStream(payload)) { | ||
return payload.bytesRead; | ||
} | ||
|
||
if (isString(payload)) { | ||
return Buffer.byteLength(payload); | ||
} | ||
|
||
if (isObject(payload)) { | ||
return Buffer.byteLength(JSON.stringify(payload)); | ||
} | ||
|
||
return undefined; | ||
} |
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
Oops, something went wrong.