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,579 @@
1
+ 'use strict'
2
+
3
+ const stream = require('node:stream')
4
+
5
+ const t = require('node:test')
6
+ const split = require('split2')
7
+ const pino = require('pino')
8
+
9
+ const Fastify = require('../../fastify')
10
+ const { on } = stream
11
+
12
+ t.test('logger options', { timeout: 60000 }, async (t) => {
13
+ t.plan(16)
14
+
15
+ await t.test('logger can be silenced', (t) => {
16
+ t.plan(17)
17
+ const fastify = Fastify({
18
+ logger: false
19
+ })
20
+ t.after(() => fastify.close())
21
+ t.assert.ok(fastify.log)
22
+ t.assert.deepEqual(typeof fastify.log, 'object')
23
+ t.assert.deepEqual(typeof fastify.log.fatal, 'function')
24
+ t.assert.deepEqual(typeof fastify.log.error, 'function')
25
+ t.assert.deepEqual(typeof fastify.log.warn, 'function')
26
+ t.assert.deepEqual(typeof fastify.log.info, 'function')
27
+ t.assert.deepEqual(typeof fastify.log.debug, 'function')
28
+ t.assert.deepEqual(typeof fastify.log.trace, 'function')
29
+ t.assert.deepEqual(typeof fastify.log.child, 'function')
30
+
31
+ const childLog = fastify.log.child()
32
+
33
+ t.assert.deepEqual(typeof childLog, 'object')
34
+ t.assert.deepEqual(typeof childLog.fatal, 'function')
35
+ t.assert.deepEqual(typeof childLog.error, 'function')
36
+ t.assert.deepEqual(typeof childLog.warn, 'function')
37
+ t.assert.deepEqual(typeof childLog.info, 'function')
38
+ t.assert.deepEqual(typeof childLog.debug, 'function')
39
+ t.assert.deepEqual(typeof childLog.trace, 'function')
40
+ t.assert.deepEqual(typeof childLog.child, 'function')
41
+ })
42
+
43
+ await t.test('Should set a custom logLevel for a plugin', async (t) => {
44
+ const lines = ['incoming request', 'Hello', 'request completed']
45
+ t.plan(lines.length + 2)
46
+
47
+ const stream = split(JSON.parse)
48
+
49
+ const loggerInstance = pino({ level: 'error' }, stream)
50
+
51
+ const fastify = Fastify({
52
+ loggerInstance
53
+ })
54
+ t.after(() => fastify.close())
55
+
56
+ fastify.get('/', (req, reply) => {
57
+ req.log.info('Not Exist') // we should not see this log
58
+ reply.send({ hello: 'world' })
59
+ })
60
+
61
+ fastify.register(function (instance, opts, done) {
62
+ instance.get('/plugin', (req, reply) => {
63
+ req.log.info('Hello') // we should see this log
64
+ reply.send({ hello: 'world' })
65
+ })
66
+ done()
67
+ }, { logLevel: 'info' })
68
+
69
+ await fastify.ready()
70
+
71
+ {
72
+ const response = await fastify.inject({ method: 'GET', url: '/' })
73
+ const body = await response.json()
74
+ t.assert.deepEqual(body.hello, 'world')
75
+ }
76
+
77
+ {
78
+ const response = await fastify.inject({ method: 'GET', url: '/plugin' })
79
+ const body = await response.json()
80
+ t.assert.deepEqual(body.hello, 'world')
81
+ }
82
+
83
+ for await (const [line] of on(stream, 'data')) {
84
+ t.assert.deepEqual(line.msg, lines.shift())
85
+ if (lines.length === 0) break
86
+ }
87
+ })
88
+
89
+ await t.test('Should set a custom logSerializers for a plugin', async (t) => {
90
+ const lines = ['incoming request', 'XHello', 'request completed']
91
+ t.plan(lines.length + 1)
92
+
93
+ const stream = split(JSON.parse)
94
+
95
+ const loggerInstance = pino({ level: 'error' }, stream)
96
+
97
+ const fastify = Fastify({
98
+ loggerInstance
99
+ })
100
+ t.after(() => fastify.close())
101
+
102
+ fastify.register(function (instance, opts, done) {
103
+ instance.get('/plugin', (req, reply) => {
104
+ req.log.info({ test: 'Hello' }) // we should see this log
105
+ reply.send({ hello: 'world' })
106
+ })
107
+ done()
108
+ }, { logLevel: 'info', logSerializers: { test: value => 'X' + value } })
109
+
110
+ await fastify.ready()
111
+
112
+ {
113
+ const response = await fastify.inject({ method: 'GET', url: '/plugin' })
114
+ const body = await response.json()
115
+ t.assert.deepEqual(body.hello, 'world')
116
+ }
117
+
118
+ for await (const [line] of on(stream, 'data')) {
119
+ // either test or msg
120
+ t.assert.deepEqual(line.test || line.msg, lines.shift())
121
+ if (lines.length === 0) break
122
+ }
123
+ })
124
+
125
+ await t.test('Should set a custom logLevel for every plugin', async (t) => {
126
+ const lines = ['incoming request', 'info', 'request completed', 'incoming request', 'debug', 'request completed']
127
+ t.plan(lines.length * 2 + 3)
128
+
129
+ const stream = split(JSON.parse)
130
+
131
+ const loggerInstance = pino({ level: 'error' }, stream)
132
+
133
+ const fastify = Fastify({
134
+ loggerInstance
135
+ })
136
+ t.after(() => fastify.close())
137
+
138
+ fastify.get('/', (req, reply) => {
139
+ req.log.warn('Hello') // we should not see this log
140
+ reply.send({ hello: 'world' })
141
+ })
142
+
143
+ fastify.register(function (instance, opts, done) {
144
+ instance.get('/info', (req, reply) => {
145
+ req.log.info('info') // we should see this log
146
+ req.log.debug('hidden log')
147
+ reply.send({ hello: 'world' })
148
+ })
149
+ done()
150
+ }, { logLevel: 'info' })
151
+
152
+ fastify.register(function (instance, opts, done) {
153
+ instance.get('/debug', (req, reply) => {
154
+ req.log.debug('debug') // we should see this log
155
+ req.log.trace('hidden log')
156
+ reply.send({ hello: 'world' })
157
+ })
158
+ done()
159
+ }, { logLevel: 'debug' })
160
+
161
+ await fastify.ready()
162
+
163
+ {
164
+ const response = await fastify.inject({ method: 'GET', url: '/' })
165
+ const body = await response.json()
166
+ t.assert.deepEqual(body, { hello: 'world' })
167
+ }
168
+
169
+ {
170
+ const response = await fastify.inject({ method: 'GET', url: '/info' })
171
+ const body = await response.json()
172
+ t.assert.deepEqual(body, { hello: 'world' })
173
+ }
174
+
175
+ {
176
+ const response = await fastify.inject({ method: 'GET', url: '/debug' })
177
+ const body = await response.json()
178
+ t.assert.deepEqual(body, { hello: 'world' })
179
+ }
180
+
181
+ for await (const [line] of on(stream, 'data')) {
182
+ t.assert.ok(line.level === 30 || line.level === 20)
183
+ t.assert.deepEqual(line.msg, lines.shift())
184
+ if (lines.length === 0) break
185
+ }
186
+ })
187
+
188
+ await t.test('Should set a custom logSerializers for every plugin', async (t) => {
189
+ const lines = ['incoming request', 'Hello', 'request completed', 'incoming request', 'XHello', 'request completed', 'incoming request', 'ZHello', 'request completed']
190
+ t.plan(lines.length + 3)
191
+
192
+ const stream = split(JSON.parse)
193
+
194
+ const loggerInstance = pino({ level: 'info' }, stream)
195
+ const fastify = Fastify({
196
+ loggerInstance
197
+ })
198
+ t.after(() => fastify.close())
199
+
200
+ fastify.get('/', (req, reply) => {
201
+ req.log.warn({ test: 'Hello' })
202
+ reply.send({ hello: 'world' })
203
+ })
204
+
205
+ fastify.register(function (instance, opts, done) {
206
+ instance.get('/test1', (req, reply) => {
207
+ req.log.info({ test: 'Hello' })
208
+ reply.send({ hello: 'world' })
209
+ })
210
+ done()
211
+ }, { logSerializers: { test: value => 'X' + value } })
212
+
213
+ fastify.register(function (instance, opts, done) {
214
+ instance.get('/test2', (req, reply) => {
215
+ req.log.info({ test: 'Hello' })
216
+ reply.send({ hello: 'world' })
217
+ })
218
+ done()
219
+ }, { logSerializers: { test: value => 'Z' + value } })
220
+
221
+ await fastify.ready()
222
+
223
+ {
224
+ const response = await fastify.inject({ method: 'GET', url: '/' })
225
+ const body = await response.json()
226
+ t.assert.deepEqual(body, { hello: 'world' })
227
+ }
228
+
229
+ {
230
+ const response = await fastify.inject({ method: 'GET', url: '/test1' })
231
+ const body = await response.json()
232
+ t.assert.deepEqual(body, { hello: 'world' })
233
+ }
234
+
235
+ {
236
+ const response = await fastify.inject({ method: 'GET', url: '/test2' })
237
+ const body = await response.json()
238
+ t.assert.deepEqual(body, { hello: 'world' })
239
+ }
240
+
241
+ for await (const [line] of on(stream, 'data')) {
242
+ t.assert.deepEqual(line.test || line.msg, lines.shift())
243
+ if (lines.length === 0) break
244
+ }
245
+ })
246
+
247
+ await t.test('Should override serializers from route', async (t) => {
248
+ const lines = ['incoming request', 'ZHello', 'request completed']
249
+ t.plan(lines.length + 1)
250
+
251
+ const stream = split(JSON.parse)
252
+
253
+ const loggerInstance = pino({ level: 'info' }, stream)
254
+ const fastify = Fastify({
255
+ loggerInstance
256
+ })
257
+ t.after(() => fastify.close())
258
+
259
+ fastify.register(function (instance, opts, done) {
260
+ instance.get('/', {
261
+ logSerializers: {
262
+ test: value => 'Z' + value // should override
263
+ }
264
+ }, (req, reply) => {
265
+ req.log.info({ test: 'Hello' })
266
+ reply.send({ hello: 'world' })
267
+ })
268
+ done()
269
+ }, { logSerializers: { test: value => 'X' + value } })
270
+
271
+ await fastify.ready()
272
+
273
+ {
274
+ const response = await fastify.inject({ method: 'GET', url: '/' })
275
+ const body = await response.json()
276
+ t.assert.deepEqual(body, { hello: 'world' })
277
+ }
278
+
279
+ for await (const [line] of on(stream, 'data')) {
280
+ t.assert.deepEqual(line.test || line.msg, lines.shift())
281
+ if (lines.length === 0) break
282
+ }
283
+ })
284
+
285
+ await t.test('Should override serializers from plugin', async (t) => {
286
+ const lines = ['incoming request', 'ZHello', 'request completed']
287
+ t.plan(lines.length + 1)
288
+
289
+ const stream = split(JSON.parse)
290
+
291
+ const loggerInstance = pino({ level: 'info' }, stream)
292
+ const fastify = Fastify({
293
+ loggerInstance
294
+ })
295
+ t.after(() => fastify.close())
296
+
297
+ fastify.register(function (instance, opts, done) {
298
+ instance.register(context1, {
299
+ logSerializers: {
300
+ test: value => 'Z' + value // should override
301
+ }
302
+ })
303
+ done()
304
+ }, { logSerializers: { test: value => 'X' + value } })
305
+
306
+ function context1 (instance, opts, done) {
307
+ instance.get('/', (req, reply) => {
308
+ req.log.info({ test: 'Hello' })
309
+ reply.send({ hello: 'world' })
310
+ })
311
+ done()
312
+ }
313
+
314
+ await fastify.ready()
315
+
316
+ {
317
+ const response = await fastify.inject({ method: 'GET', url: '/' })
318
+ const body = await response.json()
319
+ t.assert.deepEqual(body, { hello: 'world' })
320
+ }
321
+
322
+ for await (const [line] of on(stream, 'data')) {
323
+ t.assert.deepEqual(line.test || line.msg, lines.shift())
324
+ if (lines.length === 0) break
325
+ }
326
+ })
327
+
328
+ await t.test('Should increase the log level for a specific plugin', async (t) => {
329
+ const lines = ['Hello']
330
+ t.plan(lines.length * 2 + 1)
331
+
332
+ const stream = split(JSON.parse)
333
+
334
+ const loggerInstance = pino({ level: 'info' }, stream)
335
+
336
+ const fastify = Fastify({
337
+ loggerInstance
338
+ })
339
+ t.after(() => fastify.close())
340
+
341
+ fastify.register(function (instance, opts, done) {
342
+ instance.get('/', (req, reply) => {
343
+ req.log.error('Hello') // we should see this log
344
+ reply.send({ hello: 'world' })
345
+ })
346
+ done()
347
+ }, { logLevel: 'error' })
348
+
349
+ await fastify.ready()
350
+
351
+ {
352
+ const response = await fastify.inject({ method: 'GET', url: '/' })
353
+ const body = await response.json()
354
+ t.assert.deepEqual(body, { hello: 'world' })
355
+ }
356
+
357
+ for await (const [line] of on(stream, 'data')) {
358
+ t.assert.deepEqual(line.level, 50)
359
+ t.assert.deepEqual(line.msg, lines.shift())
360
+ if (lines.length === 0) break
361
+ }
362
+ })
363
+
364
+ await t.test('Should set the log level for the customized 404 handler', async (t) => {
365
+ const lines = ['Hello']
366
+ t.plan(lines.length * 2 + 1)
367
+
368
+ const stream = split(JSON.parse)
369
+
370
+ const loggerInstance = pino({ level: 'warn' }, stream)
371
+
372
+ const fastify = Fastify({
373
+ loggerInstance
374
+ })
375
+ t.after(() => fastify.close())
376
+
377
+ fastify.register(function (instance, opts, done) {
378
+ instance.setNotFoundHandler(function (req, reply) {
379
+ req.log.error('Hello')
380
+ reply.code(404).send()
381
+ })
382
+ done()
383
+ }, { logLevel: 'error' })
384
+
385
+ await fastify.ready()
386
+
387
+ {
388
+ const response = await fastify.inject({ method: 'GET', url: '/' })
389
+ t.assert.deepEqual(response.statusCode, 404)
390
+ }
391
+
392
+ for await (const [line] of on(stream, 'data')) {
393
+ t.assert.deepEqual(line.level, 50)
394
+ t.assert.deepEqual(line.msg, lines.shift())
395
+ if (lines.length === 0) break
396
+ }
397
+ })
398
+
399
+ await t.test('Should set the log level for the customized 500 handler', async (t) => {
400
+ const lines = ['Hello']
401
+ t.plan(lines.length * 2 + 1)
402
+
403
+ const stream = split(JSON.parse)
404
+
405
+ const loggerInstance = pino({ level: 'warn' }, stream)
406
+
407
+ const fastify = Fastify({
408
+ loggerInstance
409
+ })
410
+ t.after(() => fastify.close())
411
+
412
+ fastify.register(function (instance, opts, done) {
413
+ instance.get('/', (req, reply) => {
414
+ req.log.error('kaboom')
415
+ reply.send(new Error('kaboom'))
416
+ })
417
+
418
+ instance.setErrorHandler(function (e, request, reply) {
419
+ reply.log.fatal('Hello')
420
+ reply.code(500).send()
421
+ })
422
+ done()
423
+ }, { logLevel: 'fatal' })
424
+
425
+ await fastify.ready()
426
+
427
+ {
428
+ const response = await fastify.inject({ method: 'GET', url: '/' })
429
+ t.assert.deepEqual(response.statusCode, 500)
430
+ }
431
+
432
+ for await (const [line] of on(stream, 'data')) {
433
+ t.assert.deepEqual(line.level, 60)
434
+ t.assert.deepEqual(line.msg, lines.shift())
435
+ if (lines.length === 0) break
436
+ }
437
+ })
438
+
439
+ await t.test('Should set a custom log level for a specific route', async (t) => {
440
+ const lines = ['incoming request', 'Hello', 'request completed']
441
+ t.plan(lines.length + 2)
442
+
443
+ const stream = split(JSON.parse)
444
+
445
+ const loggerInstance = pino({ level: 'error' }, stream)
446
+
447
+ const fastify = Fastify({
448
+ loggerInstance
449
+ })
450
+ t.after(() => fastify.close())
451
+
452
+ fastify.get('/log', { logLevel: 'info' }, (req, reply) => {
453
+ req.log.info('Hello')
454
+ reply.send({ hello: 'world' })
455
+ })
456
+
457
+ fastify.get('/no-log', (req, reply) => {
458
+ req.log.info('Hello')
459
+ reply.send({ hello: 'world' })
460
+ })
461
+
462
+ await fastify.ready()
463
+
464
+ {
465
+ const response = await fastify.inject({ method: 'GET', url: '/log' })
466
+ const body = await response.json()
467
+ t.assert.deepEqual(body, { hello: 'world' })
468
+ }
469
+
470
+ {
471
+ const response = await fastify.inject({ method: 'GET', url: '/no-log' })
472
+ const body = await response.json()
473
+ t.assert.deepEqual(body, { hello: 'world' })
474
+ }
475
+
476
+ for await (const [line] of on(stream, 'data')) {
477
+ t.assert.deepEqual(line.msg, lines.shift())
478
+ if (lines.length === 0) break
479
+ }
480
+ })
481
+
482
+ await t.test('should pass when using unWritable props in the logger option', (t) => {
483
+ t.plan(8)
484
+ const fastify = Fastify({
485
+ logger: Object.defineProperty({}, 'level', { value: 'info' })
486
+ })
487
+ t.after(() => fastify.close())
488
+
489
+ t.assert.deepEqual(typeof fastify.log, 'object')
490
+ t.assert.deepEqual(typeof fastify.log.fatal, 'function')
491
+ t.assert.deepEqual(typeof fastify.log.error, 'function')
492
+ t.assert.deepEqual(typeof fastify.log.warn, 'function')
493
+ t.assert.deepEqual(typeof fastify.log.info, 'function')
494
+ t.assert.deepEqual(typeof fastify.log.debug, 'function')
495
+ t.assert.deepEqual(typeof fastify.log.trace, 'function')
496
+ t.assert.deepEqual(typeof fastify.log.child, 'function')
497
+ })
498
+
499
+ await t.test('Should throw an error if logger instance is passed to `logger`', async (t) => {
500
+ t.plan(2)
501
+ const stream = split(JSON.parse)
502
+
503
+ const logger = require('pino')(stream)
504
+
505
+ try {
506
+ Fastify({ logger })
507
+ } catch (err) {
508
+ t.assert.ok(err)
509
+ t.assert.deepEqual(err.code, 'FST_ERR_LOG_INVALID_LOGGER_CONFIG')
510
+ }
511
+ })
512
+
513
+ await t.test('Should throw an error if options are passed to `loggerInstance`', async (t) => {
514
+ t.plan(2)
515
+ try {
516
+ Fastify({ loggerInstance: { level: 'log' } })
517
+ } catch (err) {
518
+ t.assert.ok(err)
519
+ t.assert.strictEqual(err.code, 'FST_ERR_LOG_INVALID_LOGGER_INSTANCE')
520
+ }
521
+ })
522
+
523
+ await t.test('If both `loggerInstance` and `logger` are provided, an error should be thrown', async (t) => {
524
+ t.plan(2)
525
+ const loggerInstanceStream = split(JSON.parse)
526
+ const loggerInstance = pino({ level: 'error' }, loggerInstanceStream)
527
+ const loggerStream = split(JSON.parse)
528
+ try {
529
+ Fastify({
530
+ logger: {
531
+ stream: loggerStream,
532
+ level: 'info'
533
+ },
534
+ loggerInstance
535
+ })
536
+ } catch (err) {
537
+ t.assert.ok(err)
538
+ t.assert.deepEqual(err.code, 'FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED')
539
+ }
540
+ })
541
+
542
+ await t.test('`logger` should take pino configuration and create a pino logger', async (t) => {
543
+ const lines = ['hello', 'world']
544
+ t.plan(2 * lines.length + 2)
545
+ const loggerStream = split(JSON.parse)
546
+ const fastify = Fastify({
547
+ logger: {
548
+ stream: loggerStream,
549
+ level: 'error'
550
+ }
551
+ })
552
+ t.after(() => fastify.close())
553
+ fastify.get('/hello', (req, reply) => {
554
+ req.log.error('hello')
555
+ reply.code(404).send()
556
+ })
557
+
558
+ fastify.get('/world', (req, reply) => {
559
+ req.log.error('world')
560
+ reply.code(201).send()
561
+ })
562
+
563
+ await fastify.ready()
564
+ {
565
+ const response = await fastify.inject({ method: 'GET', url: '/hello' })
566
+ t.assert.deepEqual(response.statusCode, 404)
567
+ }
568
+ {
569
+ const response = await fastify.inject({ method: 'GET', url: '/world' })
570
+ t.assert.deepEqual(response.statusCode, 201)
571
+ }
572
+
573
+ for await (const [line] of on(loggerStream, 'data')) {
574
+ t.assert.deepEqual(line.level, 50)
575
+ t.assert.deepEqual(line.msg, lines.shift())
576
+ if (lines.length === 0) break
577
+ }
578
+ })
579
+ })