apollo-link-logger icon indicating copy to clipboard operation
apollo-link-logger copied to clipboard

Support Apollo Client v4

Open maxsalven opened this issue 2 months ago • 1 comments

This package is incompatible with Apollo Client v4. Here's a version that works.

The key change is using map from rxjs instead of forward(operation).map()

https://www.apollographql.com/docs/react/migrating/apollo-client-4-migration#observable-api-changes

import { ApolloLink } from "@apollo/client/core";
import { map } from "rxjs";

import type { OperationTypeNode } from "graphql";

export const loggerLink = new ApolloLink((operation, forward) => {
  const startTime = new Date().getTime();

  return forward(operation).pipe(
    map((result) => {
      const ellapsed = new Date().getTime() - startTime;

      const group = formatMessage(operation.operationType, operation, ellapsed);

      logging.groupCollapsed(...group);

      logging.log("INIT", operation);
      logging.log("RESULT", result);

      logging.groupEnd(...group);
      return result;
    }),
  );
});

const formatMessage = (
  operationType: OperationTypeNode,
  operation: ApolloLink.Operation,
  ellapsed: number,
) => {
  const headerCss = [
    "color: gray; font-weight: lighter", // title
    `color: ${operationType === "query" ? "#03A9F4" : "red"};`, // operationType
    "color: inherit;", // operationName
  ];

  const parts = [
    "%c apollo",
    `%c${operationType}`,
    `%c${operation.operationName}`,
  ];

  if (operationType !== "subscription") {
    parts.push(`%c(in ${ellapsed} ms)`);
    headerCss.push("color: gray; font-weight: lighter;"); // time
  }

  return [parts.join(" "), ...headerCss];
};

const bindToConsole = (consoleMethod: any, polyfill: any) => {
  return consoleMethod ? consoleMethod.bind(console) : polyfill;
};

const logging = (() => {
  let prefix = "";

  const consoleLog = (...args: any[]) => {
    console.log(prefix, ...args);
  };

  const consoleError = (...args: any[]) => {
    console.error(prefix, ...args);
  };

  const consoleGroup = (...args: any[]) => {
    consoleLog(...args);
    prefix += "> ";
  };

  const consoleGroupEnd = () => {
    prefix = prefix.slice(0, -2);
  };

  return {
    log: consoleLog,
    error: consoleError,
    group: bindToConsole(console.group, consoleGroup),
    groupCollapsed: bindToConsole(console.groupCollapsed, consoleGroup),
    groupEnd: bindToConsole(console.groupEnd, consoleGroupEnd),
  };
})();

maxsalven avatar Oct 29 '25 02:10 maxsalven

Hi, it's been a while since I've looked at any of this, would have assumed this to be default functionality by now. I have pushed a minimal version of your changes to master, we'll see.

blackxored avatar Oct 30 '25 02:10 blackxored