MarcSchaetz / vuejs3-logger

Provides customizable logging functionality for Vue.js. Compatible with Vue3.
MIT License
9 stars 4 forks source link

Implement a possibility to create multiple logger objects #2

Open MarcSchaetz opened 3 years ago

MarcSchaetz commented 3 years ago

Suggested by @chrisspiegl

Basically, the behavior of other plugins nowadays seems to be to provide a createLogger function as a named export.

This createLogger then builds the logger and also has a key install which would be used by the app.use to call with the app and possible options.

All this could then be used by the user in a plugins/logger.js to build their own logger which has the same preferences inside components and outside.

In the mean time, I basically did the same for myself with a bit of a workaround (wrapping the vuejs3-logger in it's own plugin createLogger πŸ™ˆ.

Maybe the code below will be helpful (it's workaround):

import VueLogger from 'vuejs3-logger'

const isProduction = process.env.NODE_ENV === 'production'

export const options = {
  isEnabled: true,
  logLevel: isProduction ? 'error' : 'debug',
  stringifyArguments: false,
  showLogLevel: true,
  showMethodName: true,
  separator: ':',
  showConsoleColors: true,
}

function createLogger(options) {
  return {
    install (app, installOptions = {}) {
      options = {...options, ...installOptions }
      app.use(VueLogger, options)
      console.log(`INSTALLING THE LOGGER`)
      Object.assign(this, app.$log)
    }
  }
}

const loggerCreated = createLogger(options)

// outputs only the `{ install: … }` because at this point the logger is not installed and thus the `Object.assign` was not run. This however is also not possible to do any different way without going into the guts of the `vuejs3-logger` because the necessary function (`initLoggerInstance `) is currently `private`.
// console.log(`loggerCreated:`, loggerCreated) 

export const logger = loggerCreated
export const log = loggerCreated

The improvement with official support of a createLogger function would solve all the issues and would make the logger available upon first call and not just after it actually was initiated with app.use.

Again, hope this helps and am looking forward to an update to this plugin 🌸.

Oh… and P.S.: hi from Germany πŸ‘ just a few hundred km north from you πŸš— .

Originally posted by @chrisspiegl in https://github.com/MarcSchaetz/vuejs3-logger/issues/1#issuecomment-817264400

chrisspiegl commented 3 years ago

Thank you @MarcSchaetz for brining this up as a suggestion. I think it's right to put it into it's own issue, I just thought it was related before. Here are my further findings in regards to the createLogger function posted in the other thread:

Originally posted: https://github.com/MarcSchaetz/vuejs3-logger/issues/1#issuecomment-817270130

Further findings: This time it actually worked πŸ™ˆ. The logger is now accessible outside of components and can be loaded by simply doing import { log } from '@/plugins/logger' in my project.

Please note again, I am not proficient in Typescript so this is probably "ugly" for some πŸ™ˆ.

Here is the function I added to the vue3-logger.ts file:

public createLogger(options: ILoggerOptions) {
    options = Object.assign(this.getDefaultOptions(), options);

    if (this.isValidOptions(options, this.logLevels)) {
      const $log = this.initLoggerInstance(options, this.logLevels);
      $log.install = function (Vue: any, options: ILoggerOptions) {
        Vue.provide('vuejs3-logger', $log);
        Vue.config.globalProperties.$log = $log;
      }
      return $log
    } else {
        throw new Error(this.errorMessage);
    }
}

And below is my plugins/logger.js file which loads and creates the logger.

I have not found a way to directly export the createLogger so that I can simply do a import { createLogger } from 'vuejs3-logger' for now. But maybe a official release will fix that and someone with more understanding can get that done πŸ₯‡ .

import VueLogger from 'vuejs3-logger/src'

const isProduction = process.env.NODE_ENV === 'production'

export const options = {
  isEnabled: true,
  logLevel: isProduction ? 'error' : 'debug',
  stringifyArguments: false,
  showLogLevel: true,
  showMethodName: true,
  separator: ':',
  showConsoleColors: true,
}

const loggerCreated = VueLogger.createLogger(options)

export const logger = loggerCreated
export const log = loggerCreated
MarcSchaetz commented 3 years ago

@chrisspiegl As you mentioned, the feature of adding different loggers is very common in programming.

The implementation would be easy if I just added another loggerinstance with a different key. For example:

createLogger(key: string, options: ILoggerOptions) {
  // Create logger instance
  Vue.provide(key, loggerInstance);
}

It then is possible to inject the logger into different components, classes, etc.

However the question is if this is desirable.
It needs to be checked if the performance suffers from to many loggers managed by the dependency injection system of Vue.

Another approach would be a createLogger-function which returns a local logger instance without providing it to the application.

class SomeClass {
  logger: Log

  constructor() {
    this.logger = createLogger({});
  }
]
chrisspiegl commented 3 years ago

Hi @MarcSchaetz, I think there are two separate things going on:

  1. Multiple Loggers
  2. Getting the Logger Instance globally simply by importing the plugin/logger where it got first initialized like the Vuex Store or the Vue Router.

1: Multiple Loggers

This would indeed be something that could be of interest as well, despite being my goal. Specifically for the purpose of namespacing loggers so they show more than just the function they were invoked out of.

2: Getting the Logger Instance

This is what I am after and what I think I achieved with the code shared above. The createLogger creates one logger, and provides the install function for the Vue app.use component. But at the same time it provides the already initiated logger and thus can be returned many times and with that bringing it into all kinds of systems (like the vuex store etc.)

I hope my description is good and understandable?

I am currently only after the 'injecting the one and only logger into all kinds of files πŸ‘ .

whaliendev commented 3 years ago

Thank for you all :+1:! I've been working on providing a logger instance to an external js file for a couple of days. This really helps me a lot. I'm also looking forward to an official release to provide these desired features.

54mu3l commented 2 years ago

2: Getting the Logger Instance

Any news on this?

MarcSchaetz commented 2 years ago

@54mu3l Yes. Due to me not really working with Vue in the past, I simply forgot about the logger. I looked at it again and I'm optimistic on providing some update at the weekend.

MarcSchaetz commented 2 years ago

@54mu3l @chrisspiegl Please checkout commit 5b2dfd1 and give me your opinion on it.

chrisspiegl commented 2 years ago

Hi @MarcSchaetz, I saw the change however at this point in time I am not actively coding on any of my projects where I am using VUE. When I get back to that (I do not have a timeline at this point) I will also check this out.

54mu3l commented 2 years ago

@MarcSchaetz Thank you so much for your great work!

I had a look at your commit and checked out the project. At a first glance this looks good to me...

I think the best way for me to test this, would be within my vue project. Could you publish this branch as a next-version? This would be a great help for me, since I simply could add (npm install vuejs3-logger@next) this change to my project.

Thank you!

MarcSchaetz commented 2 years ago

Hi @54mu3l I just released the next tag on npm.

54mu3l commented 2 years ago

Hi @MarcSchaetz

Great, thank you!

I just did some tests:

First of all there seems to be a problem with the types in this release. I needed to manually move index.d.ts from the dist-folder to the types-folder. To be able to use import { createLogger } from 'vuejs3-logger';

After fixing this, I tried to use vuejs3-logger the same way I use vue-i18n (see code below).

Until now my code looked like this (in case you're wondering, I'm using quasar = just ignore the boot-stuff):

import { boot } from 'quasar/wrappers';
import { VueLogger } from 'vuejs3-logger';

const isProduction = process.env.NODE_ENV !== 'development';

const options = {
  isEnabled: true,
  logLevel: isProduction ? 'error' : 'debug',
  stringifyArguments: false,
  showLogLevel: false,
  showMethodName: false,
  separator: '|',
  showConsoleColors: false,
};

export default boot(({ app }) => {
  app.use(VueLogger, options);
});

Now my new code looks like this:

import { boot } from 'quasar/wrappers';
import { createLogger } from 'vuejs3-logger';

const isProduction = process.env.NODE_ENV !== 'development';

const options = {
  isEnabled: true,
  logLevel: isProduction ? 'error' : 'debug',
  stringifyArguments: false,
  showLogLevel: false,
  showMethodName: false,
  separator: '|',
  showConsoleColors: false,
};

const logger = createLogger(options);

export default boot(({ app }) => {
  app.use(logger);
});

export { logger };

The last line enables me to import the logger instance into other non-vue-js-files. (= exactly what I want πŸ₯³)

==> There is only one big problem (using the code above): within a vue component $log is not defined

I used this temporary workaround to get it to work:

import { boot } from 'quasar/wrappers';
import { createLogger } from 'vuejs3-logger';

const isProduction = process.env.NODE_ENV !== 'development';

const options = {
  isEnabled: true,
  logLevel: isProduction ? 'error' : 'debug',
  stringifyArguments: false,
  showLogLevel: false,
  showMethodName: false,
  separator: '|',
  showConsoleColors: false,
};

const logger = createLogger(options);

export default boot(({ app }) => {
  // app.use(logger);

  app.use(VueLogger, options);
});

export { logger };

With this example I used two logger instances. One for within vue (with $log) and another one for the non-vue-stuff...


Btw this is how I'm doing the same thing with i18n:

import { boot } from 'quasar/wrappers';
import { createI18n } from 'vue-i18n';

import messages from 'src/i18n';

const i18n = createI18n({
  legacy: false,
  locale: 'en',
  messages,
});

export default boot(({ app }) => {
  // Set i18n instance on app
  app.use(i18n);
});

export { i18n };
MarcSchaetz commented 2 years ago

Hey @54mu3l

Your workaround is actually the preferred way to use it as far as I implemented it.

const options = {
  isEnabled: true,
  logLevel: isProduction ? 'error' : 'debug',
  stringifyArguments: false,
  showLogLevel: false,
  showMethodName: false,
  separator: '|',
  showConsoleColors: false,
};

export default boot(({ app }) => {
  // This line internally calls createLogger(options) but also registers
  // the logger with the key "vuejs3-logger" inside the Vue instance
  app.use(VueLogger, options);
});

// This line creates a whole new local logger object which is not
// registered in the Vue instance
const logger = createLogger(options);

export { logger };

What you however can do is use the new static register function to create a logger and register it in the Vue instance with a user defined key.

app.use(VueLogger.register("your-key"), options);

It must be called inside the app.use function to get a hold of the Vue instance.

54mu3l commented 2 years ago

Hi @MarcSchaetz

Alright, thank you!

I just did some more testing and this works perfectly for me. I guess you can publish this change, as soon as you fixed the types-problem (as mentioned above). It would probably make sense to add 1-2 lines to the readme, though.

Thanks ☺️

marco-mastella commented 1 year ago

ciao, any news on the release of this new features? i see version 2.0.0 on the repository that is not yet release on master