node-fastify 5.8.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (354) hide show
  1. package/.borp.yaml +3 -0
  2. package/.markdownlint-cli2.yaml +22 -0
  3. package/.prettierignore +1 -0
  4. package/GOVERNANCE.md +4 -0
  5. package/LICENSE +21 -0
  6. package/PROJECT_CHARTER.md +126 -0
  7. package/README.md +423 -0
  8. package/SECURITY.md +220 -0
  9. package/SPONSORS.md +24 -0
  10. package/build/build-error-serializer.js +35 -0
  11. package/build/build-validation.js +169 -0
  12. package/build/sync-version.js +11 -0
  13. package/docs/Guides/Benchmarking.md +60 -0
  14. package/docs/Guides/Database.md +321 -0
  15. package/docs/Guides/Delay-Accepting-Requests.md +608 -0
  16. package/docs/Guides/Detecting-When-Clients-Abort.md +172 -0
  17. package/docs/Guides/Ecosystem.md +726 -0
  18. package/docs/Guides/Fluent-Schema.md +127 -0
  19. package/docs/Guides/Getting-Started.md +620 -0
  20. package/docs/Guides/Index.md +43 -0
  21. package/docs/Guides/Migration-Guide-V3.md +287 -0
  22. package/docs/Guides/Migration-Guide-V4.md +267 -0
  23. package/docs/Guides/Migration-Guide-V5.md +727 -0
  24. package/docs/Guides/Plugins-Guide.md +520 -0
  25. package/docs/Guides/Prototype-Poisoning.md +383 -0
  26. package/docs/Guides/Recommendations.md +378 -0
  27. package/docs/Guides/Serverless.md +604 -0
  28. package/docs/Guides/Style-Guide.md +246 -0
  29. package/docs/Guides/Testing.md +481 -0
  30. package/docs/Guides/Write-Plugin.md +103 -0
  31. package/docs/Guides/Write-Type-Provider.md +34 -0
  32. package/docs/Reference/ContentTypeParser.md +271 -0
  33. package/docs/Reference/Decorators.md +436 -0
  34. package/docs/Reference/Encapsulation.md +194 -0
  35. package/docs/Reference/Errors.md +377 -0
  36. package/docs/Reference/HTTP2.md +94 -0
  37. package/docs/Reference/Hooks.md +958 -0
  38. package/docs/Reference/Index.md +73 -0
  39. package/docs/Reference/LTS.md +86 -0
  40. package/docs/Reference/Lifecycle.md +99 -0
  41. package/docs/Reference/Logging.md +268 -0
  42. package/docs/Reference/Middleware.md +79 -0
  43. package/docs/Reference/Plugins.md +245 -0
  44. package/docs/Reference/Principles.md +73 -0
  45. package/docs/Reference/Reply.md +1001 -0
  46. package/docs/Reference/Request.md +295 -0
  47. package/docs/Reference/Routes.md +802 -0
  48. package/docs/Reference/Server.md +2389 -0
  49. package/docs/Reference/Type-Providers.md +256 -0
  50. package/docs/Reference/TypeScript.md +1729 -0
  51. package/docs/Reference/Validation-and-Serialization.md +1130 -0
  52. package/docs/Reference/Warnings.md +58 -0
  53. package/docs/index.md +24 -0
  54. package/docs/resources/encapsulation_context.drawio +1 -0
  55. package/docs/resources/encapsulation_context.svg +3 -0
  56. package/eslint.config.js +35 -0
  57. package/examples/asyncawait.js +38 -0
  58. package/examples/benchmark/body.json +3 -0
  59. package/examples/benchmark/hooks-benchmark-async-await.js +44 -0
  60. package/examples/benchmark/hooks-benchmark.js +52 -0
  61. package/examples/benchmark/parser.js +47 -0
  62. package/examples/benchmark/simple.js +30 -0
  63. package/examples/benchmark/webstream.js +27 -0
  64. package/examples/hooks.js +91 -0
  65. package/examples/http2.js +39 -0
  66. package/examples/https.js +38 -0
  67. package/examples/parser.js +53 -0
  68. package/examples/plugin.js +12 -0
  69. package/examples/route-prefix.js +38 -0
  70. package/examples/shared-schema.js +38 -0
  71. package/examples/simple-stream.js +20 -0
  72. package/examples/simple.js +32 -0
  73. package/examples/simple.mjs +27 -0
  74. package/examples/typescript-server.ts +79 -0
  75. package/examples/use-plugin.js +29 -0
  76. package/fastify.d.ts +253 -0
  77. package/fastify.js +985 -0
  78. package/integration/server.js +29 -0
  79. package/integration/test.sh +23 -0
  80. package/lib/config-validator.js +1266 -0
  81. package/lib/content-type-parser.js +413 -0
  82. package/lib/content-type.js +160 -0
  83. package/lib/context.js +98 -0
  84. package/lib/decorate.js +152 -0
  85. package/lib/error-handler.js +173 -0
  86. package/lib/error-serializer.js +134 -0
  87. package/lib/error-status.js +14 -0
  88. package/lib/errors.js +516 -0
  89. package/lib/four-oh-four.js +190 -0
  90. package/lib/handle-request.js +195 -0
  91. package/lib/head-route.js +45 -0
  92. package/lib/hooks.js +429 -0
  93. package/lib/initial-config-validation.js +37 -0
  94. package/lib/logger-factory.js +136 -0
  95. package/lib/logger-pino.js +68 -0
  96. package/lib/noop-set.js +10 -0
  97. package/lib/plugin-override.js +90 -0
  98. package/lib/plugin-utils.js +169 -0
  99. package/lib/promise.js +23 -0
  100. package/lib/reply.js +1030 -0
  101. package/lib/req-id-gen-factory.js +52 -0
  102. package/lib/request.js +391 -0
  103. package/lib/route.js +686 -0
  104. package/lib/schema-controller.js +164 -0
  105. package/lib/schemas.js +207 -0
  106. package/lib/server.js +441 -0
  107. package/lib/symbols.js +71 -0
  108. package/lib/validation.js +280 -0
  109. package/lib/warnings.js +57 -0
  110. package/lib/wrap-thenable.js +84 -0
  111. package/package.json +225 -0
  112. package/scripts/validate-ecosystem-links.js +179 -0
  113. package/test/404s.test.js +2035 -0
  114. package/test/500s.test.js +422 -0
  115. package/test/allow-unsafe-regex.test.js +92 -0
  116. package/test/als.test.js +65 -0
  117. package/test/async-await.test.js +705 -0
  118. package/test/async-dispose.test.js +20 -0
  119. package/test/async_hooks.test.js +52 -0
  120. package/test/body-limit.test.js +224 -0
  121. package/test/buffer.test.js +74 -0
  122. package/test/build/error-serializer.test.js +36 -0
  123. package/test/build/version.test.js +14 -0
  124. package/test/build-certificate.js +109 -0
  125. package/test/bundler/README.md +29 -0
  126. package/test/bundler/esbuild/bundler-test.js +32 -0
  127. package/test/bundler/esbuild/package.json +10 -0
  128. package/test/bundler/esbuild/src/fail-plugin-version.js +14 -0
  129. package/test/bundler/esbuild/src/index.js +9 -0
  130. package/test/bundler/webpack/bundler-test.js +32 -0
  131. package/test/bundler/webpack/package.json +11 -0
  132. package/test/bundler/webpack/src/fail-plugin-version.js +14 -0
  133. package/test/bundler/webpack/src/index.js +9 -0
  134. package/test/bundler/webpack/webpack.config.js +15 -0
  135. package/test/case-insensitive.test.js +102 -0
  136. package/test/chainable.test.js +40 -0
  137. package/test/child-logger-factory.test.js +128 -0
  138. package/test/client-timeout.test.js +38 -0
  139. package/test/close-pipelining.test.js +78 -0
  140. package/test/close.test.js +706 -0
  141. package/test/conditional-pino.test.js +47 -0
  142. package/test/connection-timeout.test.js +42 -0
  143. package/test/constrained-routes.test.js +1138 -0
  144. package/test/content-length.test.js +174 -0
  145. package/test/content-parser.test.js +739 -0
  146. package/test/content-type.test.js +181 -0
  147. package/test/context-config.test.js +164 -0
  148. package/test/custom-http-server.test.js +118 -0
  149. package/test/custom-parser-async.test.js +59 -0
  150. package/test/custom-parser.0.test.js +701 -0
  151. package/test/custom-parser.1.test.js +266 -0
  152. package/test/custom-parser.2.test.js +91 -0
  153. package/test/custom-parser.3.test.js +208 -0
  154. package/test/custom-parser.4.test.js +218 -0
  155. package/test/custom-parser.5.test.js +130 -0
  156. package/test/custom-querystring-parser.test.js +129 -0
  157. package/test/decorator.test.js +1330 -0
  158. package/test/delete.test.js +344 -0
  159. package/test/diagnostics-channel/404.test.js +49 -0
  160. package/test/diagnostics-channel/async-delay-request.test.js +65 -0
  161. package/test/diagnostics-channel/async-request.test.js +64 -0
  162. package/test/diagnostics-channel/error-before-handler.test.js +35 -0
  163. package/test/diagnostics-channel/error-request.test.js +53 -0
  164. package/test/diagnostics-channel/error-status.test.js +123 -0
  165. package/test/diagnostics-channel/init.test.js +50 -0
  166. package/test/diagnostics-channel/sync-delay-request.test.js +49 -0
  167. package/test/diagnostics-channel/sync-request-reply.test.js +51 -0
  168. package/test/diagnostics-channel/sync-request.test.js +54 -0
  169. package/test/encapsulated-child-logger-factory.test.js +69 -0
  170. package/test/encapsulated-error-handler.test.js +237 -0
  171. package/test/esm/errorCodes.test.mjs +10 -0
  172. package/test/esm/esm.test.mjs +13 -0
  173. package/test/esm/index.test.js +8 -0
  174. package/test/esm/named-exports.mjs +14 -0
  175. package/test/esm/other.mjs +8 -0
  176. package/test/esm/plugin.mjs +8 -0
  177. package/test/fastify-instance.test.js +300 -0
  178. package/test/find-route.test.js +152 -0
  179. package/test/fluent-schema.test.js +209 -0
  180. package/test/genReqId.test.js +426 -0
  181. package/test/handler-context.test.js +45 -0
  182. package/test/handler-timeout.test.js +367 -0
  183. package/test/has-route.test.js +88 -0
  184. package/test/header-overflow.test.js +55 -0
  185. package/test/helper.js +496 -0
  186. package/test/hooks-async.test.js +1099 -0
  187. package/test/hooks.on-listen.test.js +1162 -0
  188. package/test/hooks.on-ready.test.js +421 -0
  189. package/test/hooks.test.js +3578 -0
  190. package/test/http-methods/copy.test.js +35 -0
  191. package/test/http-methods/custom-http-methods.test.js +114 -0
  192. package/test/http-methods/get.test.js +412 -0
  193. package/test/http-methods/head.test.js +263 -0
  194. package/test/http-methods/lock.test.js +108 -0
  195. package/test/http-methods/mkcalendar.test.js +143 -0
  196. package/test/http-methods/mkcol.test.js +35 -0
  197. package/test/http-methods/move.test.js +42 -0
  198. package/test/http-methods/propfind.test.js +136 -0
  199. package/test/http-methods/proppatch.test.js +105 -0
  200. package/test/http-methods/report.test.js +142 -0
  201. package/test/http-methods/search.test.js +233 -0
  202. package/test/http-methods/trace.test.js +21 -0
  203. package/test/http-methods/unlock.test.js +38 -0
  204. package/test/http2/closing.test.js +270 -0
  205. package/test/http2/constraint.test.js +109 -0
  206. package/test/http2/head.test.js +34 -0
  207. package/test/http2/plain.test.js +68 -0
  208. package/test/http2/secure-with-fallback.test.js +113 -0
  209. package/test/http2/secure.test.js +67 -0
  210. package/test/http2/unknown-http-method.test.js +34 -0
  211. package/test/https/custom-https-server.test.js +58 -0
  212. package/test/https/https.test.js +136 -0
  213. package/test/imports.test.js +17 -0
  214. package/test/inject.test.js +502 -0
  215. package/test/input-validation.js +335 -0
  216. package/test/internals/all.test.js +38 -0
  217. package/test/internals/content-type-parser.test.js +111 -0
  218. package/test/internals/context.test.js +31 -0
  219. package/test/internals/decorator.test.js +156 -0
  220. package/test/internals/errors.test.js +982 -0
  221. package/test/internals/handle-request.test.js +270 -0
  222. package/test/internals/hook-runner.test.js +449 -0
  223. package/test/internals/hooks.test.js +96 -0
  224. package/test/internals/initial-config.test.js +383 -0
  225. package/test/internals/logger.test.js +163 -0
  226. package/test/internals/plugin.test.js +170 -0
  227. package/test/internals/promise.test.js +63 -0
  228. package/test/internals/reply-serialize.test.js +714 -0
  229. package/test/internals/reply.test.js +1920 -0
  230. package/test/internals/req-id-gen-factory.test.js +133 -0
  231. package/test/internals/request-validate.test.js +1402 -0
  232. package/test/internals/request.test.js +506 -0
  233. package/test/internals/schema-controller-perf.test.js +40 -0
  234. package/test/internals/server.test.js +91 -0
  235. package/test/internals/validation.test.js +352 -0
  236. package/test/issue-4959.test.js +118 -0
  237. package/test/keep-alive-timeout.test.js +42 -0
  238. package/test/listen.1.test.js +154 -0
  239. package/test/listen.2.test.js +113 -0
  240. package/test/listen.3.test.js +83 -0
  241. package/test/listen.4.test.js +168 -0
  242. package/test/listen.5.test.js +122 -0
  243. package/test/logger/instantiation.test.js +341 -0
  244. package/test/logger/logger-test-utils.js +47 -0
  245. package/test/logger/logging.test.js +460 -0
  246. package/test/logger/options.test.js +579 -0
  247. package/test/logger/request.test.js +292 -0
  248. package/test/logger/response.test.js +183 -0
  249. package/test/logger/tap-parallel-not-ok +0 -0
  250. package/test/max-requests-per-socket.test.js +113 -0
  251. package/test/middleware.test.js +37 -0
  252. package/test/noop-set.test.js +19 -0
  253. package/test/nullable-validation.test.js +187 -0
  254. package/test/options.error-handler.test.js +5 -0
  255. package/test/options.test.js +5 -0
  256. package/test/output-validation.test.js +140 -0
  257. package/test/patch.error-handler.test.js +5 -0
  258. package/test/patch.test.js +5 -0
  259. package/test/plugin.1.test.js +230 -0
  260. package/test/plugin.2.test.js +314 -0
  261. package/test/plugin.3.test.js +287 -0
  262. package/test/plugin.4.test.js +504 -0
  263. package/test/plugin.helper.js +8 -0
  264. package/test/plugin.name.display.js +10 -0
  265. package/test/post-empty-body.test.js +38 -0
  266. package/test/pretty-print.test.js +366 -0
  267. package/test/promises.test.js +125 -0
  268. package/test/proto-poisoning.test.js +145 -0
  269. package/test/put.error-handler.test.js +5 -0
  270. package/test/put.test.js +5 -0
  271. package/test/register.test.js +184 -0
  272. package/test/reply-code.test.js +148 -0
  273. package/test/reply-early-hints.test.js +100 -0
  274. package/test/reply-error.test.js +815 -0
  275. package/test/reply-trailers.test.js +445 -0
  276. package/test/reply-web-stream-locked.test.js +37 -0
  277. package/test/request-error.test.js +624 -0
  278. package/test/request-header-host.test.js +339 -0
  279. package/test/request-id.test.js +118 -0
  280. package/test/request-timeout.test.js +53 -0
  281. package/test/route-hooks.test.js +635 -0
  282. package/test/route-prefix.test.js +904 -0
  283. package/test/route-shorthand.test.js +48 -0
  284. package/test/route.1.test.js +259 -0
  285. package/test/route.2.test.js +100 -0
  286. package/test/route.3.test.js +213 -0
  287. package/test/route.4.test.js +127 -0
  288. package/test/route.5.test.js +211 -0
  289. package/test/route.6.test.js +306 -0
  290. package/test/route.7.test.js +406 -0
  291. package/test/route.8.test.js +225 -0
  292. package/test/router-options.test.js +1108 -0
  293. package/test/same-shape.test.js +124 -0
  294. package/test/schema-examples.test.js +661 -0
  295. package/test/schema-feature.test.js +2198 -0
  296. package/test/schema-serialization.test.js +1171 -0
  297. package/test/schema-special-usage.test.js +1348 -0
  298. package/test/schema-validation.test.js +1572 -0
  299. package/test/scripts/validate-ecosystem-links.test.js +339 -0
  300. package/test/serialize-response.test.js +186 -0
  301. package/test/server.test.js +347 -0
  302. package/test/set-error-handler.test.js +69 -0
  303. package/test/skip-reply-send.test.js +317 -0
  304. package/test/stream-serializers.test.js +40 -0
  305. package/test/stream.1.test.js +94 -0
  306. package/test/stream.2.test.js +129 -0
  307. package/test/stream.3.test.js +198 -0
  308. package/test/stream.4.test.js +176 -0
  309. package/test/stream.5.test.js +188 -0
  310. package/test/sync-routes.test.js +32 -0
  311. package/test/throw.test.js +359 -0
  312. package/test/toolkit.js +63 -0
  313. package/test/trust-proxy.test.js +162 -0
  314. package/test/type-provider.test.js +22 -0
  315. package/test/types/content-type-parser.test-d.ts +72 -0
  316. package/test/types/decorate-request-reply.test-d.ts +18 -0
  317. package/test/types/dummy-plugin.ts +9 -0
  318. package/test/types/errors.test-d.ts +90 -0
  319. package/test/types/fastify.test-d.ts +352 -0
  320. package/test/types/hooks.test-d.ts +550 -0
  321. package/test/types/import.ts +2 -0
  322. package/test/types/instance.test-d.ts +588 -0
  323. package/test/types/logger.test-d.ts +277 -0
  324. package/test/types/plugin.test-d.ts +97 -0
  325. package/test/types/register.test-d.ts +237 -0
  326. package/test/types/reply.test-d.ts +254 -0
  327. package/test/types/request.test-d.ts +188 -0
  328. package/test/types/route.test-d.ts +553 -0
  329. package/test/types/schema.test-d.ts +135 -0
  330. package/test/types/serverFactory.test-d.ts +37 -0
  331. package/test/types/type-provider.test-d.ts +1213 -0
  332. package/test/types/using.test-d.ts +17 -0
  333. package/test/upgrade.test.js +52 -0
  334. package/test/url-rewriting.test.js +122 -0
  335. package/test/use-semicolon-delimiter.test.js +168 -0
  336. package/test/validation-error-handling.test.js +900 -0
  337. package/test/versioned-routes.test.js +603 -0
  338. package/test/web-api.test.js +616 -0
  339. package/test/wrap-thenable.test.js +30 -0
  340. package/types/content-type-parser.d.ts +75 -0
  341. package/types/context.d.ts +22 -0
  342. package/types/errors.d.ts +92 -0
  343. package/types/hooks.d.ts +875 -0
  344. package/types/instance.d.ts +609 -0
  345. package/types/logger.d.ts +107 -0
  346. package/types/plugin.d.ts +44 -0
  347. package/types/register.d.ts +42 -0
  348. package/types/reply.d.ts +81 -0
  349. package/types/request.d.ts +95 -0
  350. package/types/route.d.ts +199 -0
  351. package/types/schema.d.ts +61 -0
  352. package/types/server-factory.d.ts +19 -0
  353. package/types/type-provider.d.ts +130 -0
  354. package/types/utils.d.ts +98 -0
@@ -0,0 +1,341 @@
1
+ 'use strict'
2
+
3
+ const stream = require('node:stream')
4
+ const os = require('node:os')
5
+ const fs = require('node:fs')
6
+
7
+ const t = require('node:test')
8
+ const split = require('split2')
9
+
10
+ const { streamSym } = require('pino/lib/symbols')
11
+
12
+ const Fastify = require('../../fastify')
13
+ const helper = require('../helper')
14
+ const { FST_ERR_LOG_INVALID_LOGGER } = require('../../lib/errors')
15
+ const { once, on } = stream
16
+ const { createTempFile, request } = require('./logger-test-utils')
17
+ const { partialDeepStrictEqual } = require('../toolkit')
18
+
19
+ t.test('logger instantiation', { timeout: 60000 }, async (t) => {
20
+ let localhost
21
+ let localhostForURL
22
+
23
+ t.plan(11)
24
+ t.before(async function () {
25
+ [localhost, localhostForURL] = await helper.getLoopbackHost()
26
+ })
27
+
28
+ await t.test('can use external logger instance', async (t) => {
29
+ const lines = [/^Server listening at /, /^incoming request$/, /^log success$/, /^request completed$/]
30
+ t.plan(lines.length + 1)
31
+
32
+ const stream = split(JSON.parse)
33
+
34
+ const loggerInstance = require('pino')(stream)
35
+
36
+ const fastify = Fastify({ loggerInstance })
37
+ t.after(() => fastify.close())
38
+
39
+ fastify.get('/foo', function (req, reply) {
40
+ t.assert.ok(req.log)
41
+ req.log.info('log success')
42
+ reply.send({ hello: 'world' })
43
+ })
44
+
45
+ await fastify.listen({ port: 0, host: localhost })
46
+
47
+ await request(`http://${localhostForURL}:` + fastify.server.address().port + '/foo')
48
+
49
+ for await (const [line] of on(stream, 'data')) {
50
+ const regex = lines.shift()
51
+ t.assert.ok(regex.test(line.msg), '"' + line.msg + '" does not match "' + regex + '"')
52
+ if (lines.length === 0) break
53
+ }
54
+ })
55
+
56
+ await t.test('should create a default logger if provided one is invalid', (t) => {
57
+ t.plan(8)
58
+
59
+ const logger = new Date()
60
+
61
+ const fastify = Fastify({ logger })
62
+ t.after(() => fastify.close())
63
+
64
+ t.assert.strictEqual(typeof fastify.log, 'object')
65
+ t.assert.strictEqual(typeof fastify.log.fatal, 'function')
66
+ t.assert.strictEqual(typeof fastify.log.error, 'function')
67
+ t.assert.strictEqual(typeof fastify.log.warn, 'function')
68
+ t.assert.strictEqual(typeof fastify.log.info, 'function')
69
+ t.assert.strictEqual(typeof fastify.log.debug, 'function')
70
+ t.assert.strictEqual(typeof fastify.log.trace, 'function')
71
+ t.assert.strictEqual(typeof fastify.log.child, 'function')
72
+ })
73
+
74
+ await t.test('expose the logger', async (t) => {
75
+ t.plan(2)
76
+ const stream = split(JSON.parse)
77
+ const fastify = Fastify({
78
+ logger: {
79
+ stream,
80
+ level: 'info'
81
+ }
82
+ })
83
+ t.after(() => fastify.close())
84
+
85
+ await fastify.ready()
86
+
87
+ t.assert.ok(fastify.log)
88
+ t.assert.strictEqual(typeof fastify.log, 'object')
89
+ })
90
+
91
+ const interfaces = os.networkInterfaces()
92
+ const ipv6 = Object.keys(interfaces)
93
+ .filter(name => name.substr(0, 2) === 'lo')
94
+ .map(name => interfaces[name])
95
+ .reduce((list, set) => list.concat(set), [])
96
+ .filter(info => info.family === 'IPv6')
97
+ .map(info => info.address)
98
+ .shift()
99
+
100
+ await t.test('Wrap IPv6 address in listening log message', { skip: !ipv6 }, async (t) => {
101
+ t.plan(1)
102
+
103
+ const stream = split(JSON.parse)
104
+ const fastify = Fastify({
105
+ logger: {
106
+ stream,
107
+ level: 'info'
108
+ }
109
+ })
110
+ t.after(() => fastify.close())
111
+
112
+ await fastify.ready()
113
+ await fastify.listen({ port: 0, host: ipv6 })
114
+
115
+ {
116
+ const [line] = await once(stream, 'data')
117
+ t.assert.strictEqual(line.msg, `Server listening at http://[${ipv6}]:${fastify.server.address().port}`)
118
+ }
119
+ })
120
+
121
+ await t.test('Do not wrap IPv4 address', async (t) => {
122
+ t.plan(1)
123
+ const stream = split(JSON.parse)
124
+ const fastify = Fastify({
125
+ logger: {
126
+ stream,
127
+ level: 'info'
128
+ }
129
+ })
130
+ t.after(() => fastify.close())
131
+
132
+ await fastify.ready()
133
+ await fastify.listen({ port: 0, host: '127.0.0.1' })
134
+
135
+ {
136
+ const [line] = await once(stream, 'data')
137
+ t.assert.strictEqual(line.msg, `Server listening at http://127.0.0.1:${fastify.server.address().port}`)
138
+ }
139
+ })
140
+
141
+ await t.test('file option', async (t) => {
142
+ const { file, cleanup } = createTempFile(t)
143
+ // 0600 permissions (read/write for owner only)
144
+ if (process.env.CITGM) { fs.writeFileSync(file, '', { mode: 0o600 }) }
145
+
146
+ const fastify = Fastify({
147
+ logger: { file }
148
+ })
149
+
150
+ t.after(async () => {
151
+ await helper.sleep(250)
152
+ // may fail on win
153
+ try {
154
+ // cleanup the file after sonic-boom closed
155
+ // otherwise we may face racing condition
156
+ fastify.log[streamSym].once('close', cleanup)
157
+ // we must flush the stream ourself
158
+ // otherwise buffer may whole sonic-boom
159
+ fastify.log[streamSym].flushSync()
160
+ // end after flushing to actually close file
161
+ fastify.log[streamSym].end()
162
+ } catch (err) {
163
+ console.warn(err)
164
+ }
165
+ })
166
+ t.after(() => fastify.close())
167
+
168
+ fastify.get('/', function (req, reply) {
169
+ t.assert.ok(req.log)
170
+ reply.send({ hello: 'world' })
171
+ })
172
+
173
+ await fastify.ready()
174
+ const server = await fastify.listen({ port: 0, host: localhost })
175
+ const lines = [
176
+ { msg: `Server listening at ${server}` },
177
+ { req: { method: 'GET', url: '/' }, msg: 'incoming request' },
178
+ { res: { statusCode: 200 }, msg: 'request completed' }
179
+ ]
180
+ await request(`http://${localhostForURL}:` + fastify.server.address().port)
181
+
182
+ await helper.sleep(250)
183
+
184
+ const log = fs.readFileSync(file, 'utf8').split('\n')
185
+ // strip last line
186
+ log.pop()
187
+
188
+ let id
189
+ for (let line of log) {
190
+ line = JSON.parse(line)
191
+ if (id === undefined && line.reqId) id = line.reqId
192
+ if (id !== undefined && line.reqId) t.assert.strictEqual(line.reqId, id)
193
+ t.assert.ok(partialDeepStrictEqual(line, lines.shift()))
194
+ }
195
+ })
196
+
197
+ await t.test('should be able to use a custom logger', (t) => {
198
+ t.plan(7)
199
+
200
+ const loggerInstance = {
201
+ fatal: (msg) => { t.assert.strictEqual(msg, 'fatal') },
202
+ error: (msg) => { t.assert.strictEqual(msg, 'error') },
203
+ warn: (msg) => { t.assert.strictEqual(msg, 'warn') },
204
+ info: (msg) => { t.assert.strictEqual(msg, 'info') },
205
+ debug: (msg) => { t.assert.strictEqual(msg, 'debug') },
206
+ trace: (msg) => { t.assert.strictEqual(msg, 'trace') },
207
+ child: () => loggerInstance
208
+ }
209
+
210
+ const fastify = Fastify({ loggerInstance })
211
+ t.after(() => fastify.close())
212
+
213
+ fastify.log.fatal('fatal')
214
+ fastify.log.error('error')
215
+ fastify.log.warn('warn')
216
+ fastify.log.info('info')
217
+ fastify.log.debug('debug')
218
+ fastify.log.trace('trace')
219
+ const child = fastify.log.child()
220
+ t.assert.strictEqual(child, loggerInstance)
221
+ })
222
+
223
+ await t.test('should throw in case a partially matching logger is provided', async (t) => {
224
+ t.plan(1)
225
+
226
+ try {
227
+ const fastify = Fastify({ logger: console })
228
+ await fastify.ready()
229
+ } catch (err) {
230
+ t.assert.strictEqual(
231
+ err instanceof FST_ERR_LOG_INVALID_LOGGER,
232
+ true,
233
+ "Invalid logger object provided. The logger instance should have these functions(s): 'fatal,child'."
234
+ )
235
+ }
236
+ })
237
+
238
+ await t.test('can use external logger instance with custom serializer', async (t) => {
239
+ const lines = [['level', 30], ['req', { url: '/foo' }], ['level', 30], ['res', { statusCode: 200 }]]
240
+ t.plan(lines.length + 1)
241
+
242
+ const stream = split(JSON.parse)
243
+ const loggerInstance = require('pino')({
244
+ level: 'info',
245
+ serializers: {
246
+ req: function (req) {
247
+ return {
248
+ url: req.url
249
+ }
250
+ }
251
+ }
252
+ }, stream)
253
+
254
+ const fastify = Fastify({
255
+ loggerInstance
256
+ })
257
+ t.after(() => fastify.close())
258
+
259
+ fastify.get('/foo', function (req, reply) {
260
+ t.assert.ok(req.log)
261
+ req.log.info('log success')
262
+ reply.send({ hello: 'world' })
263
+ })
264
+
265
+ await fastify.ready()
266
+ await fastify.listen({ port: 0, host: localhost })
267
+
268
+ await request(`http://${localhostForURL}:` + fastify.server.address().port + '/foo')
269
+
270
+ for await (const [line] of on(stream, 'data')) {
271
+ const check = lines.shift()
272
+ const key = check[0]
273
+ const value = check[1]
274
+ t.assert.deepStrictEqual(line[key], value)
275
+ if (lines.length === 0) break
276
+ }
277
+ })
278
+
279
+ await t.test('The logger should accept custom serializer', async (t) => {
280
+ const stream = split(JSON.parse)
281
+ const fastify = Fastify({
282
+ logger: {
283
+ stream,
284
+ level: 'info',
285
+ serializers: {
286
+ req: function (req) {
287
+ return {
288
+ url: req.url
289
+ }
290
+ }
291
+ }
292
+ }
293
+ })
294
+ t.after(() => fastify.close())
295
+
296
+ fastify.get('/custom', function (req, reply) {
297
+ t.assert.ok(req.log)
298
+ reply.send(new Error('kaboom'))
299
+ })
300
+
301
+ await fastify.ready()
302
+ const server = await fastify.listen({ port: 0, host: localhost })
303
+ const lines = [
304
+ { msg: `Server listening at ${server}` },
305
+ { req: { url: '/custom' }, msg: 'incoming request' },
306
+ { res: { statusCode: 500 }, msg: 'kaboom' },
307
+ { res: { statusCode: 500 }, msg: 'request completed' }
308
+ ]
309
+ t.plan(lines.length + 1)
310
+
311
+ await request(`http://${localhostForURL}:` + fastify.server.address().port + '/custom')
312
+
313
+ for await (const [line] of on(stream, 'data')) {
314
+ t.assert.ok(partialDeepStrictEqual(line, lines.shift()))
315
+ if (lines.length === 0) break
316
+ }
317
+ })
318
+
319
+ await t.test('should throw in case the external logger provided does not have a child method', async (t) => {
320
+ t.plan(1)
321
+ const loggerInstance = {
322
+ info: console.info,
323
+ error: console.error,
324
+ debug: console.debug,
325
+ fatal: console.error,
326
+ warn: console.warn,
327
+ trace: console.trace
328
+ }
329
+
330
+ try {
331
+ const fastify = Fastify({ logger: loggerInstance })
332
+ await fastify.ready()
333
+ } catch (err) {
334
+ t.assert.strictEqual(
335
+ err instanceof FST_ERR_LOG_INVALID_LOGGER,
336
+ true,
337
+ "Invalid logger object provided. The logger instance should have these functions(s): 'child'."
338
+ )
339
+ }
340
+ })
341
+ })
@@ -0,0 +1,47 @@
1
+ 'use strict'
2
+
3
+ const http = require('node:http')
4
+ const os = require('node:os')
5
+ const fs = require('node:fs')
6
+
7
+ const path = require('node:path')
8
+
9
+ function createDeferredPromise () {
10
+ const promise = {}
11
+ promise.promise = new Promise(function (resolve) {
12
+ promise.resolve = resolve
13
+ })
14
+ return promise
15
+ }
16
+
17
+ let count = 0
18
+ function createTempFile () {
19
+ const file = path.join(os.tmpdir(), `sonic-boom-${process.pid}-${count++}`)
20
+ function cleanup () {
21
+ try {
22
+ fs.unlinkSync(file)
23
+ } catch { }
24
+ }
25
+ return { file, cleanup }
26
+ }
27
+
28
+ function request (url, cleanup = () => { }) {
29
+ const promise = createDeferredPromise()
30
+ http.get(url, (res) => {
31
+ const chunks = []
32
+ // we consume the response
33
+ res.on('data', function (chunk) {
34
+ chunks.push(chunk)
35
+ })
36
+ res.once('end', function () {
37
+ cleanup(res, Buffer.concat(chunks).toString())
38
+ promise.resolve()
39
+ })
40
+ })
41
+ return promise.promise
42
+ }
43
+
44
+ module.exports = {
45
+ request,
46
+ createTempFile
47
+ }