Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeError: winston.transports.MongoDB is not a constructor #171

Open
miktam opened this issue Apr 9, 2020 · 23 comments
Open

TypeError: winston.transports.MongoDB is not a constructor #171

miktam opened this issue Apr 9, 2020 · 23 comments

Comments

@miktam
Copy link

miktam commented Apr 9, 2020

When trying to instantiate following error is thrown

TypeError: winston.transports.MongoDB is not a constructor

Source code:

const winston = require('winston')
require('winston-mongodb')
const transport = new winston.transports.MongoDB({db: 'url'})

Version of the library:

"winston-mongodb": "^5.0.1"

@miktam miktam changed the title TypeError: winston.transports.MongoDB is not a function TypeError: winston.transports.MongoDB is not a constructor Apr 9, 2020
@alexander9306
Copy link

alexander9306 commented Jun 27, 2020

Any updates on this? I am having the same problem

@KathiravanBalasubramanian
Copy link

KathiravanBalasubramanian commented Jul 29, 2020

Hello @miktam,
I thing you are missing the mongodb connection string.
Try below:
const winston = require('winston');
require('winston-mongodb');
const transport = new winston.transports.MongoDB({ db: 'mongodb://hostname/collectionname' });

@miktam
Copy link
Author

miktam commented Aug 3, 2020

@KathiravanBalasubramanian nope, it's not the reason, unfortunately.

@verbal-assassin
Copy link

Again, has there been any updates on this? Literally dropping of the face of the earth does not inspire confidence. Simply stating 'missing the connection string' is not helpful.

@yurijmikhalevich
Copy link
Member

@verbal-assassin do you use the latest version of winston-mongodb and winston? Which version of node do you use?

@verbal-assassin @miktam

Can you check that the issue is present with the latest version of winston-mongodb and winston? If the issue persists can you please share your node version and a code snippet that reproduces the issue?

@chrisvoo
Copy link

chrisvoo commented Nov 1, 2020

Similar problem here: Property 'MongoDB' does not exist on type 'Transports'. My versions:

  • winston@3.3.3
  • winston-mongodb@5.0.5
  • typescript@4.0.3
  • Node: v15.0.0
  • OS: Windows 10
import { createLogger, format, transports } from 'winston';
import 'winston-mongodb';

const { combine, timestamp, json, colorize,
    prettyPrint, simple, errors,
} = format;

const finalMongoOptions = {
    db: process.env.MONGO_URI,
    level: process.env.LOGGING_LEVEL,
    name: 'mongodb',
    collection: process.env.MONGO_LOGGING_COLLECTION || 'logs',
    decolorize: true,
    tryReconnect: true,
    options: {
        useUnifiedTopology: true,
        useNewUrlParser: true,
    },
};

if (Number.isInteger(process.env.LOGS_EXPIRE_AFTER_DAYS)) {
    finalMongoOptions.expireAfterSeconds = process.env.LOGS_EXPIRE_AFTER_DAYS;
}

const logger = createLogger({
    // https://github.com/winstonjs/winston#logging-levels
    level: process.env.LOGGING_LEVEL,
    // https://github.com/winstonjs/winston#formats
    format: combine(
        // https://github.com/taylorhakes/fecha format
        timestamp({ format: 'DD-MM-YY HH:mm:ss' }),
        prettyPrint({ depth: 5 }),
        json(),
        errors({ stack: true }),
    ),
    // https://github.com/winstonjs/winston#transports
    transports: [
        new transports.Console({
            level: process.env.LOGGING_LEVEL || ERROR_LEVELS.debug.name,
            format: combine(
                colorize(),
                simple()
            ),
        }),
        new transports.MongoDB(finalMongoOptions), // ERROR HERE
    ],
    // https://github.com/winstonjs/winston#to-exit-or-not-to-exit
    exitOnError: false,
});

export default logger;

The issue occurs also with Node LTS (14.15.0)

@saurabhsinghhauhan
Copy link

@chrisvoo Did you get any solution?

@chrisvoo
Copy link

@chrisvoo Did you get any solution?

Nope, at the moment to bypass that error I just did:

const transports: any = winston.transports

@chrisvoo
Copy link

@saurabhsinghhauhan this for me works:

import {
  createLogger, format, transports, Logger,
} from 'winston';
import { MongoDB, MongoDBConnectionOptions } from 'winston-mongodb';

export type LogLevel = 'error' | 'warn' | 'info' | 'verbose' | 'debug' | 'silly'

export type BootrapWinstonOptions = {
  mongoOptions: {
    db: string
    level?: LogLevel
    collection?: string
    options?: any // MongoClient's options
    expireAfterSeconds?: number
  }
  exitOnError?: boolean
}

/**
 * It creates a Logger instance
 * @param {object} options It contains all the options used to build the logger.
 * - `level (string)`: see `ERROR_LEVELS`, default "debug"
 * @returns {Logger}
 */
export default function buildLogger(options: BootrapWinstonOptions): Logger {
  const {
    combine,
    timestamp,
    json,
    colorize,
    prettyPrint,
    simple,
    errors,
  } = format;

  const { mongoOptions } = options;

  // see https://docs.mongodb.com/manual/reference/connection-string/
  if (!mongoOptions?.db) {
    throw new Error(
      "'mongoOptions' is missing or it's missing its property 'db' (Mongo's connection string)",
    );
  }

  const finalMongoOptions: MongoDBConnectionOptions = {
    db: mongoOptions.db,
    level: mongoOptions.level ?? 'debug',
    name: 'mongodb',
    collection: mongoOptions.collection ?? 'log',
    decolorize: true,
    tryReconnect: true,
    options: mongoOptions.options ?? {
      useUnifiedTopology: true,
      useNewUrlParser: true,
    },
  };

  if (Number.isInteger(mongoOptions.expireAfterSeconds)) {
    finalMongoOptions.expireAfterSeconds = mongoOptions.expireAfterSeconds;
  }

  return createLogger({
    level: finalMongoOptions.level,
    format: combine(
      // https://github.com/taylorhakes/fecha format
      timestamp({ format: 'DD-MM-YY HH:mm:ss' }),
      prettyPrint({ depth: 5 }),
      json(),
      errors({ stack: true }),
    ),
    // https://github.com/winstonjs/winston#transports
    transports: [
      new transports.Console({
        level: process.env.NODE_ENV === 'production' ? 'info' : 'debug',
        format: combine(colorize(), simple()),
      }),
      new MongoDB(finalMongoOptions),
    ],
    // https://github.com/winstonjs/winston#to-exit-or-not-to-exit
    exitOnError:
      typeof options.exitOnError === 'boolean'
        ? options.exitOnError
        : false,
  });
}

buildLogger is just a configurable function for building a Logger. Anyway MongoDB comes from this module, not from winston. This is the Jest test that proves it:

import { MongoClient } from 'mongodb';
import buildLogger from '../src/logger';

it('Creates the collection and insert the logs', (done) => {
  const logger = buildLogger({
    mongoOptions: {
      db: 'mongodb://localhost:27017/test_mongolog',
      expireAfterSeconds: 120,
    },
    exitOnError: true,
  });

  // eslint-disable-next-line no-unused-vars
  logger.on('finish', (info) => {
    const url = 'mongodb://localhost:27017';
    const dbName = 'test_mongolog';

    MongoClient.connect(url, { useUnifiedTopology: true }, (err, client) => {
      if (err) {
        throw err;
      }

      const testDb = client.db(dbName);
      // we verify that we have one log in the last 5 seconds
      testDb
        .collection('log')
        .find({
          timestamp: {
            $lt: new Date(),
            $gte: new Date(Date.now() - 5000),
          },
        })
        .toArray()
        .then((docs) => {
          expect(docs.length).toBe(1);
          expect(docs[0].meta.key).toBe(5);
          client.close();
          done();
        });
    });
  });

  logger.info('A message', {
    metadata: {
      key: 5,
    },
  });
  logger.end();
});

@yurijmikhalevich
Copy link
Member

Can you check whether the issue persists with @5.0.6?

@Kevin-Aaaquil
Copy link

winston@^3.3.3
winston-mongodb@^5.0.7
node@16.2.0

import winston from 'winston'
import {MongoDB} from 'winston-mongodb'
import config from '../configs'
import { format, createLogger} from 'winston'
const {combine, timestamp, errors, json} = format;
const transports: any = winston.transports
const buildProdLog = ()=>{
    return createLogger({
        level: 'info',
        format: combine(
            timestamp({format : 'YYYY-MM-DD HH:mm:ss ZZ'}),
            errors({stack : true}),
            json()
        ),
        defaultMeta:{service : 'user-service'},
        transports: [
            new transports.Console(),
            new transports.File({filename : './LOGS/PROD.log'}),
            new transports.MongoDB({
                level : "info",
                db : config.MONGO_URI,
                options:{
                    ignoreUndefined: true,
                    useUnifiedTopology: true
                },
                collection : "production-logs"
            })
        ],
    });
}

export {buildProdLog}

I am still facing this error

  new transports.MongoDB({
            ^

TypeError: transports.MongoDB is not a constructor

@cloudworkpro-dave
Copy link

I'm also facing this error as well

@cloudworkpro-dave
Copy link

@yurijmikhalevich How come this issue was closed? Was there ever a solution for it?

@yurijmikhalevich
Copy link
Member

@Kevin-Aaaquil, thanks for checking and providing the example.

@mikkelking
Copy link

I have the same problem, but only when I have cloned the winston-mongodb repo (v5.0.7) and used npm link to link it into my app. Even without modifications to the code, the problem exists, and when I remove the npm link it works fine again. It doesn't make a lot of sense, as there is no build step for the repo, it's just the code.

@mikkelking
Copy link

Update on this one - my mind's background processes couldn't let it go.

I think it's something to do with the module dependencies, because sometimes it complained (after I had done npm link without doing an npm install) of a missing mongodb, but when I did an npm i it would ignore my npm-linked copy of the code.

I forked the repo as https://github.com/Back2bikes/winston-mongodb, and then installed it from there:

In the dependencies section of package.json:

  "winston-mongodb": "git+https://github.com/Back2bikes/winston-mongodb.git",

It installs and runs perfectly, so I have an element of success, but I still don't know why the npm link broke it.

@wbt
Copy link

wbt commented Jan 10, 2022

I wonder if this has core cause in common with winstonjs/winston#1814 and if those having difficulty might have an issue in git setup?

@lexNwimue
Copy link

Did anyone eventually find a fix for this?

@miktam
Copy link
Author

miktam commented Apr 28, 2023

a possible workaround that worked for us is adding the parentheses for winston.transports.MongoDB.

const transport = new (winston.transports.MongoDB)({db: 'url'})

@lexNwimue
Copy link

lexNwimue commented Apr 28, 2023

Here's my code snippet:

import { transports, format, createLogger } from "winston";
import("winston-mongodb");
import { config } from "dotenv";

config();

console.log(process.env.DB_URI);

export const usersLogger = createLogger({
  format: format.combine(format.timestamp()),
  transports: [
    new transports.File({
      filename: "logs/users-error.log",
      level: "error",
    }),

    new transports.MongoDB({
      level: "error",
      db: process.env.DB_URI,
      options: {
        useUnifiedTopology: true,
      },
      collection: "logs",
      format: format.combine(
        format.timestamp(),
        // Convert logs to a json format
        format.json()
      ),
    }),
  ],
});

export const reportsLogger = createLogger({
  format: format.combine(format.timestamp()),
  transports: [
    new transports.File({
      filename: "logs/users-error.log",
      level: "error",
    }),
    new transports.MongoDB({
      level: "error",
      db: process.env.DB_URI,
      options: {
        useUnifiedTopology: true,
      },
      collection: "logs",
      format: format.combine(
        format.timestamp(),
        // Convert logs to a json format
        format.json()
      ),
    }),
  ],
});

I'm new to logging and somehow I fail to see how I can integrate your suggestion here. 

@lexNwimue
Copy link

lexNwimue commented May 2, 2023

So, I found a fix that works for me.

import { transports, format, createLogger } from "winston";
import("winston-mongodb");
import { config } from "dotenv";

import { MongoDB } from "winston-mongodb"; // <-- THIS WAS THE MAIN DIFFERENCE

config();

const mongoOptions = {
  db: process.env.DB_URI,
  level: "error",
  options: {
    useUnifiedTopology: true,
    useNewUrlParser: true,
  },
  collection: "logs",
  format: format.combine(
    format.timestamp(),
    format.json()
  ),
};

export const logger = createLogger({
  format: format.combine(format.timestamp()),
  transports: [
    new transports.File({
      filename: "logs/users-error.log",
      level: "error",
    }),

    new MongoDB(mongoOptions), // <-- This replaced "new transports.MongoDB({options})"
  ],
});

@Ng1n3
Copy link

Ng1n3 commented Jun 9, 2024

Hi, here is how i was able to get mine working while still using types/interfaces

import express, { Request, Response } from "express";
import dotenv from "dotenv";
import expressWinston from "express-winston";
import { error, format, level, transports } from "winston";
import "winston-mongodb";
import {
  MongoDBTransportInstance,
  MongoDB,
  MongoDBConnectionOptions,
} from "winston-mongodb";
dotenv.config();

const app = express();
const PORT = Number(process.env.PORT);

const mongoOptions: MongoDBConnectionOptions = {
  db: 'mongodb://localhost:27017/logs',
  collection: "logs",
};

app.use(
  expressWinston.logger({
    transports: [
      new transports.Console(),
      new transports.File({ level: "warn", filename: "userWarning.log" }),
      new transports.File({ level: "error", filename: "userErrors.log" }),
      new MongoDB(mongoOptions),
    ],
    format: format.combine(
      format.json(),
      format.timestamp(),
      format.prettyPrint()
    ),
    statusLevels: true,
  })
);

app.get("/", (req: Request, res: Response) => {
  res.status(200).send({ message: "hello world" });
});

app.get("/400", (req: Request, res: Response) => {
  res.status(400).send({ message: "warning" });
});

app.get("/500", (req: Request, res: Response) => {
  res.status(500).send({ message: "errors" });
});

app.listen(PORT, () => {
  console.log(`App is listening on http://localhost:${PORT}`);
});

@Yuniac
Copy link

Yuniac commented Aug 23, 2024

So, I found a fix that works for me.

import { transports, format, createLogger } from "winston";
import("winston-mongodb");
import { config } from "dotenv";

import { MongoDB } from "winston-mongodb"; // <-- THIS WAS THE MAIN DIFFERENCE

config();

const mongoOptions = {
  db: process.env.DB_URI,
  level: "error",
  options: {
    useUnifiedTopology: true,
    useNewUrlParser: true,
  },
  collection: "logs",
  format: format.combine(
    format.timestamp(),
    format.json()
  ),
};

export const logger = createLogger({
  format: format.combine(format.timestamp()),
  transports: [
    new transports.File({
      filename: "logs/users-error.log",
      level: "error",
    }),

    new MongoDB(mongoOptions), // <-- This replaced "new transports.MongoDB({options})"
  ],
});

Your solution worked for me too, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests