Giter VIP home page Giter VIP logo

apollo-log's Introduction

Apollo Server

tests cover size

apollo-log

A logging plugin for Apollo GraphQL Server

โค๏ธ Please consider Sponsoring my work

apollo-server doesn't ship with any comprehensive logging, and instead offloads that responsiblity to the users and the resolvers or context handler This module provides uniform logging for the entire GraphQL request lifecycle, as provided by plugin hooks in apollo-server. The console/terminal result of which will resemble the image below:

Requirements

apollo-log is an evergreen ๐ŸŒฒ module.

This module requires an Active LTS Node version (v10.23.1+).

Install

Using npm:

npm install apollo-log

Usage

Setting up apollo-log is straight-forward. Import and call the plugin function, passing any desired options, and pass the plugin in an array to apollo-server.

import { ApolloLogPlugin } from 'apollo-log';
import { ApolloServer } from 'apollo-server';

const options = { ... };
const plugins = [ApolloLogPlugin(options)];
const apollo = new ApolloServer({
  plugins,
  ...
});

Please see the Apollo Plugins documentation for more information.

Options

events

Type: Record<string, boolean>
Default:

{
  didEncounterErrors: true,
  didResolveOperation: false,
  executionDidStart: false,
  parsingDidStart: false,
  responseForOperation: false,
  validationDidStart: false,
  willSendResponse: true
}

Specifies which Apollo lifecycle events will be logged. The requestDidStart event is always logged, and by default didEncounterErrors and willSendResponse are logged.

mutate

Type: Function Default: (data: Record<string, string>) => Record<string, string>

If specified, allows inspecting and mutating the data logged to the console for each message.

prefix

Type: String
Default: apollo

Specifies a prefix, colored by level, prepended to each log message.

timestamp

Type: Boolean

If true, will prepend a timestamp in the HH:mm:ss format to each log message.

Meta

CONTRIBUTING

LICENSE (Mozilla Public License)

apollo-log's People

Contributors

arjansingh avatar joeyfigaro avatar markhughes avatar middric avatar shellscape avatar tennox avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

apollo-log's Issues

Values of variables

Hi,
What do you think about new option that enable log values of variables?

Apollo Logger throws error when we use this with apollo gateway

  • Webpack Version: 4.41.5
  • Operating System (or Browser): Google Chrome v80.0.3987.163 on MacOS 10.15.4
  • Node Version: v10.15.3
  • webpack-plugin-serve Version: 0.12.1

How Do We Reproduce?

When we use this extension with the apolloserver asoociated with apollo gateway it throws error on the playground

Code segment is below

import express from 'express';
import { ApolloServer } from 'apollo-server-express';
import fs from 'fs';
import https from 'https';
import http from 'http';
import { ApolloGateway } from '@apollo/gateway';
import cookieParser from 'cookie-parser';
import { serviceList } from './src/helpers';
const { ApolloLogExtension } = require( 'apollo-log' );

/* Setting port for the server */
const port = process.env.PORT || 4000;
const app = express();

/* Mount cookie parker */
app.use( cookieParser() );

const extensions = [ () => new ApolloLogExtension( {
  level: 'info',
  timestamp: true,
} ) ];

/* Defining the Apollo Gateway */
const apiGateway = new ApolloGateway( {
  serviceList: serviceList
} );

/*  Creating the server based on the environment */
const server = process.env.NODE_ENV !== 'test'
  ? https.createServer(
    {
      key: fs.readFileSync( ( process.env.SSL_KEY ) ? `${ process.env.SSL_KEY }` : '' ),
      cert: fs.readFileSync( ( process.env.SSL_CERT ) ? `${ process.env.SSL_CERT }` : '' )
    },
    app
  )
  : http.createServer( app );
/* Binding the gateway with the apollo server and extracting the schema */
( async () => {
  const { schema, executor } = await apiGateway.load();
  /* Defining the Apollo Server */
  const apollo = new ApolloServer( {
    schema: schema,
    executor: executor,
    playground: process.env.NODE_ENV !== 'production',
    subscriptions: false,
    formatError: error => ( {
      message: error.message,
      locations: error.locations,
      stack: error.stack ? error.stack.split( '\n' ) : [],
      path: error.path,
    } ),
    extensions
  },
  );

  /* Applying apollo middleware to express server */
  apollo.applyMiddleware( { app } );
  server.listen( { port: port }, () => {
    console.log( `Gateway Running on port ${ port }` );
  } );
} )();

export default server;

Error that we get on playground is

{
  "error": {
    "errors": [
      {
        "message": "this[MAP][key].join is not a function",
        "stack": []
      }
    ]
  }
}

Logging to rolling file

Feature Use Case

Would like to use a logger, ie. winston to write to a log file

Feature Proposal

Could include a simple example ?

Documentation Is:

  • [ x] Missing
  • [x ] Needed
  • [x ] Confusing
  • Not Sure?

Please Explain in Detail...

I am trying to figure out how to use this - it looks promising - does it only display to the console or does it also create a log file ?

Your Proposal for Changes

Using as plugin instead of extension

Is anything else required to use it as plugin instead of extension?
Just wondering because I think that the extensions are now deprecated in apollo-server

Expose extra info to mutate callback

Feature Use Case

Expose the context (requestContext) in the mutate` callback, this way we can grab HTTP, misc. context, headers, operationName, variables, etc, and log extra breadcrumbs (such as a session id from headers) to log as a single key for logging systems.

Feature Proposal

All implementation like so:

--      mutate: (data) => {
++      mutate: (data, { http, operationName }) => {

This way we can cherry pick the variables we need from context with our extra logging requirements!

ignoredOps is not working, allowing introspectionQuerys to be logged

I thought ignoring introspection queries made sense and I thought it made sense as an option with default set to false. Anyway I realised you have a ignoredOps flag but it is being ignored on account of the operationName property being in a different place.

  • apollo-server Version: [email protected]
  • Operating System (or Browser): windows 10, firefox latest
  • Node Version: v16.13.1
  • apollo-log Version: 1.1.0

How Do We Reproduce?

At least on my system, an out of the box install with apollo-server-express and apollo-logs will start logging introspectionQuerys.

Expected Behavior

introspectionQuerys are ignored by default

Actual Behavior

log fills up with introspectionQuerys

Observations

Changing this line:

https://github.com/edzillion/apollo-log/blob/0b33bcd29f17ca8d321586b4770fe1c779ff96cb/src/index.ts#L66

To:

const operationName = context.operationName || context.request.operationName;
const ignore = ignoredOps.includes(operationName || '');

And this line:
https://github.com/edzillion/apollo-log/blob/0b33bcd29f17ca8d321586b4770fe1c779ff96cb/src/index.ts#L73

To:
operationName: operationName,

and also add a flag to the response handler to ignore introspectionQuery reponses too:
https://github.com/edzillion/apollo-log/blob/0b33bcd29f17ca8d321586b4770fe1c779ff96cb/src/index.ts#L110

options.events.willSendResponse && !ignore && log(operationId, { event: 'response', metrics, context });

will produce the expected behaviour. Perhaps this was a change added in Apollo 3?

Using the `mutate` function modifies the original request to the server

  • apollo-server Version: "apollo-server-express": "^2.25.2",
  • Operating System (or Browser): not relevant
  • Node Version: FROM node:12.19.0-alpine3.10
  • apollo-log Version: ^1.1.0

Using the mutate function modifies the original request to the server when modified. It therefore cannot fulfill its purpose as it is and can lead to nasty errors.

How Do We Reproduce?

Modify the request variables during requestDidStart in ApolloLogPlugin({mutate: (data: LogMutateData) => {...}} and see the server use the newly modified variables in its request.

Expected Behavior

The logging framework should be separate from the graphql server. The influence should be apollo -> apollo-log and not in any case apollo-log -> apollo.

Actual Behavior

Using the mutate function modifies the original request to the server when modified.

Suggested solution/workaround

const plugins = [
  {...},
  ApolloLogPlugin({
    mutate: (data: LogMutateData) => {
      // We need to deep clone the object in order to not modify the actual request
      const dataCopy = copyInstance(data)

      // mask password if part of the query
      if (dataCopy.context.request.variables && dataCopy.context.request.variables.password) {
        dataCopy.context.request.variables.password = '***'
      }

      // mask token at all times
      dataCopy.context.context.token = '***'

      return dataCopy
    },
  }),
]

WIth:

const copyInstance = (instance: any) => {
  const data = Object.assign(
    Object.create(Object.getPrototypeOf(instance)),
    JSON.parse(JSON.stringify(instance)),
  )
  return data
}

This seems to work just fine - tho long terms test are not conducted yet.
Maybe the library can either document this problem or provide a solution which ensures performance (not cloning stuff on every request)

To ensure correct behaviour you can do the following:

console.log(data.context.request.variables)
console.log(dataCopy.context.request.variables)

References

This Problem occurred in: https://github.com/gradido/gradido

PR implementing suggested fix in our service: gradido/gradido#1477

Relevant files:

You can also use this project to reproduce the issue.
Feel free to get in touch on Discord: Dornhoeschen#4105

Further notices & Disclaimer

Please inform me if I am using your library wrongly leading to this error.

I believe this could also be the result of using apollo-server-express instead of apollo-server.

Stringify call seems to unformat logs on Windows

  • apollo-server Version: [email protected]
  • Operating System (or Browser): windows 10, firefox latest
  • Node Version: v16.13.1
  • apollo-log Version: 1.1.0

How Do We Reproduce?

I suspect this is OS specific. To repro just use apollo-log as normal on a windows 10 machine. I am using conemu as my terminal but the same happens on windows default cmd

Expected Behavior

The logs are displayed with linebreaks etc so that they can be easily read.

apollo 44d6e2 {
  event: 'request',
  operationName: 'AddUser',
  query: 'mutation AddUser($addUserInput: AddUserInput!) {\n' +
    '  addUser(addUserInput: $addUserInput) {\n' +
    '    id\n' +
    '    device_id\n' +
    '    favourites\n' +
    '    __typename\n' +
    '  }\n' +
    '}',
  variables: [ 'addUserInput' ],
  context: {
    logger: Logger {
      name: 'apollo-server',
      levels: [Object],
      methodFactory: [Function: defaultMethodFactory],
      getLevel: [Function (anonymous)],
      setLevel: [Function (anonymous)],
      setDefaultLevel: [Function (anonymous)],
      resetLevel: [Function (anonymous)],
      enableAll: [Function (anonymous)],
      disableAll: [Function (anonymous)],
      trace: [Function: noop],
      debug: [Function: noop],
      info: [Function: bound info],
      warn: [Function: bound warn],
      error: [Function: bound error],
      log: [Function: noop]
    },
    schema: GraphQLSchema {
      __validationErrors: [],
      description: undefined,

Actual Behavior

Server is running on http://localhost:4000/graphql
apollo 21d17c {"event":"request","query":"    query IntrospectionQuery {      __schema {                queryType { name }        mutationType { name }        subscriptionType { name }        types {          ...FullType        }        directives {          name          description                    locations          args {            ...InputValue          }        }      }    }    fragment FullType on __Type {      kind      name      description            fields(includeDeprecated: true) {        name        description        args {          ...InputValue        }        type {          ...TypeRef        }        isDeprecated        deprecationReason      }      inputFields {        ...InputValue
  }      interfaces {        ...TypeRef      }      enumValues(includeDeprecated: true) {        name        description        isDeprecated        deprecationReason      }      possibleTypes {        ...TypeRef      }    }    fragment InputValue on __InputValue {      name      description      type { ...TypeRef }      defaultValue                }    fragment TypeRef on __Type {      kind      name      ofType {        kind        name        ofType {          kind
   name          ofType {            kind            name            ofType {              kind              name              ofType {                kind                name                ofType {                  kind
name                  ofType {

Observations

So the problem arises from the call to stringify() here:

log[(data as any).errors ? 'error' : 'info'](chalk`{dim ${id}}`, stringify(mutated));

when I removed stringify() and just returned the mutated variable the formatting was correct (as shown in expected behaviour above).
log[(data as any).errors ? 'error' : 'info'](chalk`{dim ${id}}`, mutated);

also I removed the line deleting newline chars in the query here

https://github.com/edzillion/apollo-log/blob/0b33bcd29f17ca8d321586b4770fe1c779ff96cb/src/index.ts#L69

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.