function ecsFormat()

in packages/ecs-pino-format/index.js [35:212]


function ecsFormat (opts) {
  // istanbul ignore next
  opts = opts || {}
  const convertErr = opts.convertErr != null ? opts.convertErr : true
  const convertReqRes = opts.convertReqRes != null ? opts.convertReqRes : false
  const apmIntegration = opts.apmIntegration != null ? opts.apmIntegration : true

  let apm = null
  if (apmIntegration) {
    // istanbul ignore if
    if (opts && opts._elasticApm) {
      // `opts._elasticApm` is an internal/testing-only option to be used
      // for testing in the APM agent where the import is a local path
      // rather than "elastic-apm-node".
      elasticApm = opts._elasticApm
    } else if (!triedElasticApmImport) {
      triedElasticApmImport = true
      // We lazily require this module here instead of at the top-level to
      // avoid a possible circular-require if the user code does
      // `require('@elastic/ecs-pino-format')` and has a "node_modules/"
      // where 'elastic-apm-node' shares the same ecs-pino-format install.
      try {
        elasticApm = require('elastic-apm-node')
      } catch (ex) {
        // Silently ignore.
      }
    }
    if (elasticApm && elasticApm.isStarted && elasticApm.isStarted()) {
      apm = elasticApm
    }
  }

  let serviceName = opts.serviceName
  if (serviceName == null && apm) {
    // istanbul ignore next
    serviceName = (apm.getServiceName
      ? apm.getServiceName() // added in elastic-apm-node@3.11.0
      : apm._conf.serviceName) // fallback to private `_conf`
  }

  let serviceVersion = opts.serviceVersion
  // istanbul ignore next
  if (serviceVersion == null && apm) {
    serviceVersion = (apm.getServiceVersion
      ? apm.getServiceVersion() // added in elastic-apm-node@...
      : apm._conf.serviceVersion) // fallback to private `_conf`
  }

  let serviceEnvironment = opts.serviceEnvironment
  if (serviceEnvironment == null && apm) {
    // istanbul ignore next
    serviceEnvironment = (apm.getServiceEnvironment
      ? apm.getServiceEnvironment() // added in elastic-apm-node@...
      : apm._conf.environment) // fallback to private `_conf`
  }

  let serviceNodeName = opts.serviceNodeName
  if (serviceNodeName == null && apm) {
    // istanbul ignore next
    serviceNodeName = (apm.getServiceNodeName
      ? apm.getServiceNodeName() // added in elastic-apm-node@...
      : apm._conf.serviceNodeName) // fallback to private `_conf`
  }

  let eventDataset = opts.eventDataset
  if (eventDataset == null && serviceName) {
    eventDataset = serviceName
  }

  let wasBindingsCalled = false
  function addStaticEcsBindings (obj) {
    obj['ecs.version'] = version
    if (serviceName) { obj['service.name'] = serviceName }
    if (serviceVersion) { obj['service.version'] = serviceVersion }
    if (serviceEnvironment) { obj['service.environment'] = serviceEnvironment }
    if (serviceNodeName) { obj['service.node.name'] = serviceNodeName }
    if (eventDataset) { obj['event.dataset'] = eventDataset }
  }

  const ecsPinoOptions = {
    messageKey: 'message',
    timestamp: () => `,"@timestamp":"${new Date().toISOString()}"`,
    formatters: {
      level (label, number) {
        return { 'log.level': label }
      },

      bindings (bindings) {
        const {
          // `pid` and `hostname` are default bindings, unless overriden by
          // a `base: {...}` passed to logger creation.
          pid,
          hostname,
          // name is defined if `log = pino({name: 'my name', ...})`
          name,
          ...ecsBindings
        } = bindings

        if (pid !== undefined) {
          // https://www.elastic.co/guide/en/ecs/current/ecs-process.html#field-process-pid
          ecsBindings['process.pid'] = pid
        }
        if (hostname !== undefined) {
          // https://www.elastic.co/guide/en/ecs/current/ecs-host.html#field-host-hostname
          ecsBindings['host.hostname'] = hostname
        }
        if (name !== undefined) {
          // https://www.elastic.co/guide/en/ecs/current/ecs-log.html#field-log-logger
          ecsBindings['log.logger'] = name
        }

        // With `pino({base: null, ...})` the `formatters.bindings` is *not*
        // called. In this case we need to make sure to add our static bindings
        // in `log()` below.
        wasBindingsCalled = true
        addStaticEcsBindings(ecsBindings)

        return ecsBindings
      },

      log (obj) {
        const {
          req,
          res,
          err,
          ...ecsObj
        } = obj

        if (!wasBindingsCalled) {
          addStaticEcsBindings(ecsObj)
        }

        if (apm) {
          // https://www.elastic.co/guide/en/ecs/current/ecs-tracing.html
          const tx = apm.currentTransaction
          if (tx) {
            ecsObj['trace.id'] = tx.traceId
            ecsObj['transaction.id'] = tx.id
            const span = apm.currentSpan
            // istanbul ignore else
            if (span) {
              ecsObj['span.id'] = span.id
            }
          }
        }

        // https://www.elastic.co/guide/en/ecs/current/ecs-http.html
        if (err !== undefined) {
          if (!convertErr) {
            ecsObj.err = err
          } else {
            formatError(ecsObj, err)
          }
        }

        // https://www.elastic.co/guide/en/ecs/current/ecs-http.html
        if (req !== undefined) {
          if (!convertReqRes) {
            ecsObj.req = req
          } else {
            formatHttpRequest(ecsObj, req)
          }
        }
        if (res !== undefined) {
          if (!convertReqRes) {
            ecsObj.res = res
          } else {
            formatHttpResponse(ecsObj, res)
          }
        }

        return ecsObj
      }
    }
  }

  return ecsPinoOptions
}