This plugin is designed to provide visibility into how many/what network requests are made by your GraphQL Operations. This tool is primarily targeted for existing graphql projects that have grown large and complex with integrations and developers want some insight into how heavy specific GraphQL operations are in order to identify cache or optimization candidates. Below is an example of possible log output of the plugin:
useNetworkViewer {"operationName":"test","document":"query test {\n test\n}","observations":[{"label":"HTTP/HTTPS","data":{"calls":1,"hosts":["localhost"],"requests":[{"time":1659986144633,"method":"GET","host":"localhost","port":"8883","headers":{},"response":{"time":1659986144636,"httpVersion":"1.1","statusCode":200,"headers":{"server":"stubby/5.1.0 node/v14.19.3 (darwin arm64)","x-stubby-resource-id":"1","date":"Mon, 08 Aug 2022 19:15:44 GMT","connection":"close","transfer-encoding":"chunked"},"statusMessage":"OK"},"duration_ms":3}]}}]}
Prettified output:
{
"operationName": "test",
"document": "query test {\n test\n}",
"observations": [
{
"label": "HTTP/HTTPS",
"data": {
"calls": 1,
"hosts": [
"localhost"
],
"requests": [
{
"time": 1659986144633,
"method": "GET",
"host": "localhost",
"port": "8883",
"headers": {},
"response": {
"time": 1659986144636,
"httpVersion": "1.1",
"statusCode": 200,
"headers": {
"server": "stubby/5.1.0 node/v14.19.3 (darwin arm64)",
"x-stubby-resource-id": "1",
"date": "Mon, 08 Aug 2022 19:15:44 GMT",
"connection": "close",
"transfer-encoding": "chunked"
},
"statusMessage": "OK"
},
"duration_ms": 3
}
]
}
}
]
}
Keep in mind, that this is an investigative tool that can have a heavy impact on your logs. It should only be turned on for explicit data collection activities.
Supporting concurrent requests relies on using Continuation-local storage, which has a performance cost, and so it isn't enabled by default. If your use case is not lambda like (node process serves one request at a time), then you will need to enable concurrency support for the plugin.
Use the enableConcurrencySupport
configuration option to enable concurrency support.
Add the useNetworkViewer plugin to your envelop configuration. Note the constructor takes two parameters:
- The first parameter is a boolean determining if the plugin is enabled. You must explicitly enable the plugin (recommended w/ an env variable)
- The second parameter is the configuration for the plugin
const useNetworkViewerConfig = {
// plugin options
};
const getEnveloped = envelop({
plugins: [
// all enabled plugins
useNetworkViewer(boolean(process.env.USE_NETWORK_VIEWER), useNetworkViewerConfig)
]
})
Below is a list of configuration properties and what they do
property | default | description |
---|---|---|
additionalObservers | empty array | Only the http/https observer is included by default. You must specify other observers that are use case specific (knex, redis, mysql, etc) |
logFunction | console.log | Specify what function is used to log network viewer info. You can specify your own logger (myLogger.debug for instance) |
logGraphQlDocument | false | Set to true to include the graphql operation in the log message |
enableConcurrencySupport | false | Support concurrent requests |
These additional observers aren't included by default. They are purpose specific observers that will only be applicable to some app stacks.
If your application uses Prisma, you'll want to include the PrismaObserver
in your configuration of the plugin.
The prisma client observer provides observations for your database interactions using the prisma client.
You'll need to initialize the prisma client and pass it as a parameter when instantiating the PrismaObserver
.
Then pass the PrismaObserver
instance in the additionalObservers
configuration.
const prisma = new PrismaClient()
const useNetworkViewerConfig = {
additionalObservers: [new PrismaObserver(prisma)]
};
const getEnveloped = envelop({
plugins: [
useNetworkViewer(true, useNetworkViewerConfig)
]
})
If your application uses Sequelize, you'll want to include the SequelizeObserver
in your configuration of the plugin.
The sequelize observer provides observations for your database interactions using the sequelize client.
You'll need to initialize the sequelize client and pass it as a parameter when instantiating the SequelizeObserver
.
Then pass the SequelizeObserver
instance in the additionalObservers
configuration.
const sequelize = new Sequelize('sqlite::memory:');
const useNetworkViewerConfig = {
additionalObservers: [new SequelizeObserver(sequelize)]
};
const getEnveloped = envelop({
plugins: [
useNetworkViewer(true, useNetworkViewerConfig)
]
})
If your application uses Knex.js, you'll want to include the KnexObserver
in your configuration of the plugin.
The Knex observer provides observations for your database interactions using the Knex client.
You'll need to initialize the Knex client and pass it as a parameter when instantiating the KnexObserver
.
Then pass the KnexObserver
instance in the additionalObservers
configuration.
const knex = Knex({
client: 'sqlite3',
connection: {
filename: ':memory:',
},
});
const useNetworkViewerConfig = {
additionalObservers: [new KnexObserver(knex)]
};
const getEnveloped = envelop({
plugins: [
useNetworkViewer(true, useNetworkViewerConfig)
]
})
If your application uses TypeORM, you'll want to include the TypeORMObserver
in your configuration of the plugin.
The TypeORM observer provides observations for your database interactions using the TypeORM datasource.
You'll need to initialize the TypeORM datasource with options.logger
set to an instance of TypeORMObserverLogger
.
Then pass the instance of the TypeORMObserverLogger
when instantiating the TypeORMObserver
.
Finally, pass the TypeORMObserver
instance in the additionalObservers
configuration.
const typeOrmObserverLogger = new TypeOrmObserverLogger();
const datasource = new DataSource({
type: 'sqlite',
database: ':memory:',
logger: typeOrmObserverLogger,
logging: ['error'], // still respected
});
const useNetworkViewerConfig = {
additionalObservers: [new TypeORMObserver(typeOrmObserverLogger)]
};
const getEnveloped = envelop({
plugins: [
useNetworkViewer(true, useNetworkViewerConfig)
]
})
If you've already configured your datasource with logger
and logging
value, you can provide those to TypeORMObserverLogger
instead.
The TypeORMObserverLogger
will pass all logging to the provided logger.
Example, to use one the built-in file logger to log query errors then you would use the following
to initialize the TypeORMObserverLogger
const typeOrmObserverLogger = new TypeOrmObserverLogger(
"file", /* or any valid DataSourceOptions.logger value */
['error'] /* or any valid DataSourceOptions.logging value */)
);