Repository: fastify/fastify
File: fastify.js (JavaScript)

Code before:
  }, options.ajv)
  const frameworkErrors = options.frameworkErrors

  // Ajv options
  if (!ajvOptions.customOptions || Object.prototype.toString.call(ajvOptions.customOptions) !== '[object Object]') {
    throw new FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_OBJ(typeof ajvOptions.customOptions)
  }
  if (!ajvOptions.plugins || !Array.isArray(ajvOptions.plugins)) {
    throw new FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_ARR(typeof ajvOptions.plugins)
  }

  // Instance Fastify components

  // create a default logger and then overwrite if valid logger options provided
  let logger
  let hasLogger

  if (options.loggerInstance || options.logger) {
    const { createLogger } = require('./lib/logger');
    ({ logger, hasLogger } = createLogger(options))
  } else {
    const nullLogger = require('abstract-logging')
    logger = nullLogger
    logger.child = () => logger
    hasLogger = false
  }

  // Update the options with the fixed values
  options.connectionTimeout = options.connectionTimeout || defaultInitOptions.connectionTimeout
  options.keepAliveTimeout = options.keepAliveTimeout || defaultInitOptions.keepAliveTimeout
  options.maxRequestsPerSocket = options.maxRequestsPerSocket || defaultInitOptions.maxRequestsPerSocket
  options.requestTimeout = options.requestTimeout || defaultInitOptions.requestTimeout
  options.logger = logger
  options.requestIdHeader = requestIdHeader
  options.requestIdLogLabel = requestIdLogLabel
  options.disableRequestLogging = disableRequestLogging
  options.ajv = ajvOptions
  options.clientErrorHandler = options.clientErrorHandler || defaultClientErrorHandler

  const initialConfig = getSecuredInitialConfig(options)

  // exposeHeadRoutes have its default set from the validator
  options.exposeHeadRoutes = initialConfig.exposeHeadRoutes

  // Default router
  const router = buildRouting({
    config: {
      defaultRoute,
      onBadUrl,
      constraints: options.constraints,
      ignoreTrailingSlash: options.ignoreTrailingSlash || defaultInitOptions.ignoreTrailingSlash,

Review comment (refactor):
I thought a bit more and while the solution LGTM, but let me push this code forward:
we are moving some logger logic outside the `/logger` and `/logger-factory` in the `fastify.js` file and, while it works, it does not feel perfect.

Here we could write the old:

```
const { logger, hasLogger } = createLogger(options)
```

Then, in `lib/logger-factory.js` we may expose a `createLogger` function that will look like (dirty code):

```js
function createLogger() {
  if (options.loggerInstance || options.logger) {
    const pinoLoggerFactory = require('./lib/logger-pino');
    return pinoLoggerFactory(options)
  } else {
    const nullLogger = require('abstract-logging')
    logger = nullLogger
    logger.child = () => logger
    return { logger, hasLogger: false }
  }
}
```

Where `logger-pino.js` is the old `lib/logger.js`.

This would clean up a bit the code because atm:

- the logger optimization lives in fastify.js
- the pino logger lives in `lib/logger.js`
- the abstract logger lives in fastify.js

With a proposal solution:

- fasitfy.js does not care about logging optimizations
- pino logger lives in `lib/logger-pino.js`
- abstract logger lives in `lib/logger-factory.js` (we may move it to its own file, but for 3 lines of code this would be just silly 😄 )

how does it sound to you?


Code after:
  }, options.ajv)
  const frameworkErrors = options.frameworkErrors

  // Ajv options
  if (!ajvOptions.customOptions || Object.prototype.toString.call(ajvOptions.customOptions) !== '[object Object]') {
    throw new FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_OBJ(typeof ajvOptions.customOptions)
  }
  if (!ajvOptions.plugins || !Array.isArray(ajvOptions.plugins)) {
    throw new FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_ARR(typeof ajvOptions.plugins)
  }

  // Instance Fastify components

  const { logger, hasLogger } = createLogger(options)

  // Update the options with the fixed values
  options.connectionTimeout = options.connectionTimeout || defaultInitOptions.connectionTimeout
  options.keepAliveTimeout = options.keepAliveTimeout || defaultInitOptions.keepAliveTimeout
  options.maxRequestsPerSocket = options.maxRequestsPerSocket || defaultInitOptions.maxRequestsPerSocket
  options.requestTimeout = options.requestTimeout || defaultInitOptions.requestTimeout
  options.logger = logger
  options.requestIdHeader = requestIdHeader
  options.requestIdLogLabel = requestIdLogLabel
  options.disableRequestLogging = disableRequestLogging
  options.ajv = ajvOptions
  options.clientErrorHandler = options.clientErrorHandler || defaultClientErrorHandler

  const initialConfig = getSecuredInitialConfig(options)

  // exposeHeadRoutes have its default set from the validator
  options.exposeHeadRoutes = initialConfig.exposeHeadRoutes

  // Default router
  const router = buildRouting({
    config: {
      defaultRoute,
      onBadUrl,
      constraints: options.constraints,
      ignoreTrailingSlash: options.ignoreTrailingSlash || defaultInitOptions.ignoreTrailingSlash,
      ignoreDuplicateSlashes: options.ignoreDuplicateSlashes || defaultInitOptions.ignoreDuplicateSlashes,
      maxParamLength: options.maxParamLength || defaultInitOptions.maxParamLength,
      caseSensitive: options.caseSensitive,
      allowUnsafeRegex: options.allowUnsafeRegex || defaultInitOptions.allowUnsafeRegex,
      buildPrettyMeta: defaultBuildPrettyMeta,
      querystringParser: options.querystringParser,
      useSemicolonDelimiter: options.useSemicolonDelimiter ?? defaultInitOptions.useSemicolonDelimiter
    }
  })

  // 404 router, used for handling encapsulated 404 handlers
  const fourOhFour = build404(options)