export function getHttpDebugLogPlugin()

in packages/middleware-http-debug-log/src/getHttpDebugLogPlugin.ts [87:246]


export function getHttpDebugLogPlugin(options: HttpDebugLoggingOptions = {}) {
  const optionsObject: Required<Exclude<HttpDebugLoggingOptions, string>> = {
    request: {},
    response: {},
    logger: console,
  };
  if (typeof options === "string") {
    const [line, header, body, formatted] = [
      options.includes("line"),
      options.includes("header"),
      options.includes("body"),
      options.includes("formatted"),
    ];
    if (line || header || body || formatted) {
      optionsObject.request.command = true;
      optionsObject.request.client = true;
      optionsObject.request.url = true;
      optionsObject.request.method = true;
      optionsObject.response.statusCode = true;
    }
    if (header) {
      optionsObject.request.headers = true;
      optionsObject.response.headers = true;
    }
    if (body || formatted) {
      optionsObject.request.body = true;
      optionsObject.response.body = true;
    }
    if (formatted) {
      optionsObject.request.formatBody = true;
      optionsObject.response.formatBody = true;
    }
  } else {
    Object.assign(optionsObject, options);
  }

  return {
    applyToStack: (middlewareStack: MiddlewareStack<any, any>) => {
      middlewareStack.addRelativeTo(
        (next: DeserializeHandler<any, any>, context: HandlerExecutionContext) =>
          async (args: DeserializeHandlerArguments<any>) => {
            let result: any = undefined;
            let error: unknown = undefined;
            let request: HttpRequest | unknown = undefined;
            let response: HttpResponse | unknown;

            try {
              result = await next(args);
              request = args.request;
              response = result.response;
            } catch (e) {
              error = e;
              response = e.$response;
              if (response && e.$responseBodyText) {
                (response as HttpResponse).body = fromUtf8(e.$responseBodyText);
              }
            }

            if (HttpRequest.isInstance(request) && HttpResponse.isInstance(response)) {
              const logger = optionsObject.logger;
              const line: string[] = [];
              if (optionsObject.response.statusCode) {
                line.push(String(response.statusCode));
              }
              if (optionsObject.request.method) {
                line.push(request.method);
              }
              const { clientName = "UnknownClient", commandName = "UnknownCommand" } = context;
              if (optionsObject.request.client) {
                line.push(clientName);
              }
              if (optionsObject.request.command) {
                line.push(commandName);
              }
              logger.debug(line.join(" "));
              const indentation = line.length ? 4 : 0;

              if (optionsObject.request.url) {
                let auth = "";
                if (request.username != null || request.password != null) {
                  const username = request.username ?? "";
                  const password = "***";
                  auth = `${username}:${password}@`;
                }

                const { port, path } = request;
                const url = `${request.protocol}//${auth}${request.hostname}${port ? `:${port}` : ""}${path}`;
                logger.debug(indent(indentation, url));
                if (Object.keys(request.query).length) {
                  logger.debug(indent(4, ">> Request URL queryParams: " + JSON.stringify(request.query, null, 2)));
                }
              }
              if (optionsObject.request.headers) {
                const headers = {
                  ...request.headers,
                };
                for (const key in headers) {
                  if (key.toLowerCase().match(/security|-token/)) {
                    headers[key] = "***";
                  }
                  if (key.toLowerCase() === "authorization") {
                    let value = "***";
                    if (headers[key].match(/Credential=[A-Z0-9]+/)) {
                      value = headers[key]
                        .replace(/Credential=[A-Z0-9\w]+/, "Credential=***")
                        .replace(/Signature=\w+/, "Signature=***");
                    }
                    headers[key] = value;
                  }
                }
                logger.debug(indent(indentation, ">>== Request Headers: " + JSON.stringify(headers, null, 2)));
              }
              if (optionsObject.request.body) {
                const body = await (async () => {
                  if (typeof request.body === "string") {
                    return fromUtf8(request.body);
                  }
                  try {
                    return await headStream(request.body, Infinity);
                  } catch (e) {
                    return fromUtf8(request.body ? String(request.body) : "");
                  }
                })();
                const text = format(body, optionsObject.request.formatBody);
                logger.debug(indent(indentation, `>>>=== Request Body Start ======`));
                logger.debug(indent(indentation, text));
                logger.debug(indent(indentation, `>>>=== Request Body End ======`));
                request.body = body;
              }

              if (optionsObject.response.headers) {
                logger.debug(
                  indent(indentation, "<<== Response Headers: " + JSON.stringify(response.headers, null, 2))
                );
              }
              if (optionsObject.response.body) {
                const bodyBytes = await headStream(response.body, Infinity);
                const text = format(bodyBytes, optionsObject.response.formatBody);
                logger.debug(indent(indentation, `<<<=== Response Body Start ======`));
                logger.debug(indent(indentation, text));
                logger.debug(indent(indentation, `<<<=== Response Body End ======`));
                response.body = bodyBytes;
              }
            }

            if (error) {
              throw error;
            }
            return result;
          },
        {
          toMiddleware: "deserializerMiddleware",
          relation: "after",
          name: "httpDebugLogMiddleware",
          override: true,
        }
      );
    },
  };
}