Migrating Hive Gateway from v1 to v2
This document guides you through the process of migrating your Hive Gateway from version 1 to version 2. It outlines the key changes, potential breaking points, and provides step-by-step instructions to ensure a smooth transition.
v2 includes several breaking changes and improvements over v1. The most significant changes are:
Hive Logger
The Hive Logger is a new feature in v2 that provides enhanced logging capabilities. It allows you to
log messages at different levels (info, debug, error) and provides a more structured way to handle
logs. The logger implementation now consistently uses the new @graphql-hive/logger
package and
standardizes the logger prop naming and usage.
You can read more about the new logger and its features in the Hive Logger documentation and how it works with Hive Gateway in Logging and Error Handling documentation.
Deprecating the Old Logger
The old logger interface from @graphql-mesh/types
or @graphql-mesh/utils
, the DefaultLogger
and the LogLevel
enum have been deprecated and will be removed in the future, after all components
are migrated to the new logger.
- import { DefaultLogger, LogLevel } from '@graphql-mesh/utils';
- const logger = new DefaultLogger(undefined, LogLevel.debug);
+ import { Logger } from '@graphql-hive/logger';
+ const log = new Logger({ level: 'debug' });
Logging uses similar methods as before, with two significant changes:
- The first, optional, argument of the logging methods are now the metadata
- The message supports interpolation of all values succeeding the message
- logger.debug(`Hello ${'world'}`, { foo: 'bar' });
+ log.debug({ foo: 'bar' }, 'Hello %s', 'world');
logging
Configuration Option
The logging
option has been changed to accept either:
true
to enable and log using theinfo
levelfalse
to disable logging altogether- A Hive Logger instance
- A string log level (e.g.,
debug
,info
,warn
,error
)
Changing the Log Level
import {
defineConfig,
- LogLevel,
} from '@graphql-hive/gateway';
export const gatewayConfig = defineConfig({
- logging: LogLevel.debug,
+ logging: 'debug',
});
Dynamically Changing the Log Level
A great new feature of the Hive Logger is the ability to change the log level dynamically at runtime. This allows you to adjust the verbosity of logs without restarting the application.
Please advise the Hive Logger documentation for more details and an example.
Using a Custom Logger
import {
defineConfig,
- DefaultLogger,
- LogLevel,
+ Logger,
} from '@graphql-hive/gateway';
export const gatewayConfig = defineConfig({
- logging: new DefaultLogger(undefined, LogLevel.debug),
+ logging: new Logger({ level: 'debug' }),
});
The Environment Variable
Hive Logger will continue to support the DEBUG=1
environment variable for enabling debug logging.
But, additionally, it supports the new LOG_LEVEL
environment variable for setting a specific log
level. This allows you to control the log level without modifying the code or configuration files.
For example, setting LOG_LEVEL=debug
will enable debug logging, while LOG_LEVEL=warn
will set
the log level to “warn”.
Logging in JSON Format
Previously, the Hive Gateway used two different environment variables to trigger loggin in JSON format:
LOG_FORMAT=json
NODE_ENV=production
Both of those variables are now removed and replaced with LOG_JSON=1
.
Pretty Logging
In addition to the JSON format, Hive Gateway had an additional LOG_FORMAT=pretty
environment
variable that pretty-printed the logs. This variable has been removed.
When using the default logger, the logs are now pretty-printed by default. This means that the logs will be formatted in a human-readable way, making it easier to read and understand.
Additionally, if you’re using the JSON format, you can use
LOG_JSON_PRETTY=1
environment variable to enable pretty-printing the JSON logs.
Prop Renaming logger
to log
Throughout the codebase, the logger
prop has been renamed to log
. This change is part of the
standardization effort to ensure consistency across all components and plugins. The new log
prop
is now used in all APIs, contexts, and plugin options. It’s shorter and more intuitive, making it
easier to understand and use.
Context
The context object passed to plugins and hooks now uses log
instead of logger
. Basically, the
GatewayConfigContext
interface has been changed to:
- import type { Logger as LegacyLogger } from '@graphql-mesh/types';
+ import type { Logger as HiveLogger } from '@graphql-hive/logger';
export interface GatewayConfigContext {
- logger: LegacyLogger;
+ log: HiveLogger;
// ...rest of the properties
}
Same goes for all of the transports’ contexts. Each of the transport contexts now has a log
prop
instead of logger
. Additionally, the logger is required and will always be provided.
- import type { Logger as LegacyLogger } from '@graphql-mesh/types';
+ import type { Logger as HiveLogger } from '@graphql-hive/logger';
export interface TransportContext {
- logger?: LegacyLogger;
+ log: HiveLogger;
// ...rest of the properties
}
Plugin Setup
import { defineConfig } from '@graphql-hive/gateway';
import { myPlugins } from './my-plugins';
export const gatewayConfig = defineConfig({
plugins(ctx) {
- ctx.logger.info('Loading plugins...');
+ ctx.log.info('Loading plugins...');
return [...myPlugins];
},
});
Plugin Hooks
Across all plugins, hooks and contexts, the logger
prop has been renamed to log
and will always
be provided.
It is now the highly recommended to use the logger from the context at all times because it contains the necessary metadata for increased observability, like the request ID or the execution step.
import { defineConfig } from '@graphql-hive/gateway';
export const gatewayConfig = defineConfig({
- plugins({ log }) {
+ plugins() {
return [
{
onExecute({ context }) {
- log.info('Executing...');
+ context.log.info('Executing...');
},
onDelegationPlan(context) {
- log.info('Creating delegation plan...');
+ context.log.info('Creating delegation plan...');
},
onSubgraphExecute(context) {
- log.info('Executing on subgraph...');
+ context.log.info('Executing on subgraph...');
},
onFetch({ context }) {
- log.info('Fetching data...');
+ context.log.info('Fetching data...');
},
},
];
},
});
Will log with the necessary metadata for increased observability, like this:
2025-04-10T14:00:00.000Z INF Executing...
requestId: "0b1dce69-5eb0-4d7b-97d8-1337535a620e"
2025-04-10T14:00:00.000Z INF Creating delegation plan...
requestId: "0b1dce69-5eb0-4d7b-97d8-1337535a620e"
subgraph: "accounts"
2025-04-10T14:00:00.000Z INF Executing on subgraph...
requestId: "0b1dce69-5eb0-4d7b-97d8-1337535a620e"
subgraph: "accounts"
2025-04-10T14:00:00.000Z INF Fetching data...
requestId: "0b1dce69-5eb0-4d7b-97d8-1337535a620e"
Affected Plugins
Prometheus i.e. usePrometheus
The monitoring plugin usePrometheus
has been updated to use the new logger API. The logger
prop
has been replaced with the log
prop when using Hive Gateway runtime.
import { createGatewayRuntime } from '@graphql-hive/gateway-runtime'
import usePrometheus from '@graphql-mesh/plugin-prometheus'
export const gateway = createGatewayRuntime({
plugins: ctx => [
usePrometheus({
...ctx,
- logger: ctx.logger,
+ log: ctx.log,
})
]
})
If you have been using the usePrometheus
plugin following the example from
Monitoring and Tracing, where the ctx
argument
is simply spread to the plugin options - you don’t have to change anything.
Custom Transport
If you have implemented and been using a custom transport of yours, you will need to update the
logger
prop to log
in the getSubgraphExecutor
method.
import type { Transport } from '@graphql-mesh/transport-common';
import { letterExecutor } from './my-letter-executor';
export interface LetterTransportOptions {
shouldStamp?: boolean;
}
export default {
getSubgraphExecutor(payload) {
- payload.logger.info('Creating letter executor...');
+ payload.log.info('Creating letter executor...');
return letterExecutor(payload);
},
} satisfies Transport<LetterTransportOptions>;
Custom Logger Adapters
The new Hive Logger is designed to be extensible and allows you to create custom logger adapters by
implementing “log writers” instead of the complete logger interface. The LogWriter
is simply:
import { Attributes, LogLevel } from '@graphql-hive/logger'
interface LogWriter {
write(
level: LogLevel,
attrs: Attributes | null | undefined,
msg: string | null | undefined
): void | Promise<void>
}
As you may see, it’s very simple and allows you, to not only use your favourite logger like pino or winston, but also implement custom writers that send logs to a HTTP consumer or writes to a file.
Read more about implementing your own writers in the Hive Logger documentation.
Pino (only Node.js)
Use the Node.js pino
logger library for writing Hive Logger’s
logs.
pino
is an optional peer dependency, so you must install it first.
npm i pino pino-pretty
Since we’re using a custom log writter, you have to install the Hive Logger package too:
npm i @graphql-hive/logger
import pino from 'pino'
import { defineConfig } from '@graphql-hive/gateway'
import { Logger } from '@graphql-hive/logger'
- import { createLoggerFromPino } from '@graphql-hive/logger-pino'
+ import { PinoLogWriter } from '@graphql-hive/logger/writers/pino'
const pinoLogger = pino({
transport: {
target: 'pino-pretty'
}
})
export const gatewayConfig = defineConfig({
- logging: createLoggerFromPino(pinoLogger)
+ logging: new Logger({
+ writers: [new PinoLogWriter(pinoLogger)]
+ })
})
Winston (only Node.js)
Use the Node.js winston
logger library for writing Hive
Logger’s logs.
winston
is an optional peer dependency, so you must install it first.
npm i winston
Since we’re using a custom log writter, you have to install the Hive Logger package too:
npm i @graphql-hive/logger
import { createLogger, format, transports } from 'winston'
import { defineConfig } from '@graphql-hive/gateway'
import { Logger } from '@graphql-hive/logger'
- import { createLoggerFromWinston } from '@graphql-hive/winston'
+ import { WinstonLogWriter } from '@graphql-hive/logger/writers/winston'
const winstonLogger = createLogger({
level: 'info',
format: format.combine(format.timestamp(), format.json()),
transports: [new transports.Console()]
})
export const gatewayConfig = defineConfig({
- logging: createLoggerFromWinston(winstonLogger)
+ logging: new Logger({
+ writers: [new WinstonLogWriter(winstonLogger)]
+ })
})