simc / logger

Small, easy to use and extensible logger which prints beautiful logs.
https://pub.dev/packages/logger
MIT License
1.07k stars 128 forks source link

Is it worth to put logger in a singleton? #57

Open hectorAguero opened 4 years ago

hectorAguero commented 4 years ago

So, currently I use logger like this way

///logger.dart file
final Logger logger = Logger(printer: PrettyPrinter());
///main.dart file
void main() {
  logger.d(
      'Run with either `dart example/main.dart` or `dart --enable-asserts example/main.dart`.');
}

But I read some info about singleton in dart, so don't know if I win something using it this way

///logger.dart file
class Log {
  factory Log() => _instance;
  Log._privateConstructor();
  static final Log _instance = Log._privateConstructor();

  final Logger log = Logger(
    printer: PrettyPrinter(), // Use the PrettyPrinter to format and print log
  );
}
///main.dart file
void main() {
  Log().log.d(
      'Run with either `dart example/main.dart` or `dart --enable-asserts example/main.dart`.');
}
haarts commented 4 years ago

I don't think it matters in this case. I would keep your code simple to understand. And I don't think the singleton pattern helps to make the code understandable.

In general I'm not a fan of globals and I pass my logger instances to my classes directly. It is a dependency of my class and as such I want to treat it that way. It goes counter to the accepted norm but I believe explicitness matters.

sultanmyrza commented 4 years ago

I agree with @hectorAguero it is more intuitive becase we use print("some text") not Printer().print("some text")

for my side project I use logger as singleton and here is example code


class LoggerService {
  Logger _logger;

  static final LoggerService _instance = LoggerService._internal();

  static Logger instance = Logger();

  factory LoggerService() {
    return _instance;
  }

  LoggerService._internal() {
    // add initialization logic if needed example: Logger(printer: PrettyPrinter(methodCount: 0));
    _logger = Logger();
  }
}

void main() {
  LoggerService.instance.d('Log message with 2 methods');

  LoggerService.instance.i('Info message');

  LoggerService.instance.w('Just a warning!');

  LoggerService.instance.e('Error! Something bad happened', 'Test Error');

  LoggerService.instance.v({'key': 5, 'value': 'something'});
}
fernando-s97 commented 4 years ago

I would also prefer the singleton approach.

IanWorthington commented 3 years ago

I suspect that, though I haven't tested it, the initialisation clock needs to be a singleton so that it has the same offset for different Logger instances, no?

yyong37 commented 2 years ago

class Log {
  late Logger _logger;

  Log._internal() {

    _logger = Logger();
  }

  static Logger to = _instance._logger;

  factory Log() => _instance;

  static late final Log _instance = Log._internal();

  static void v(dynamic message) {
    to.v(message);
  }

  static void d(dynamic message) {
    to.d(message);
  }

  static void i(dynamic message) {
    to.i(message);
  }

  static void w(dynamic message) {
    to.w(message);
  }

  static void e(dynamic message) {
    to.e(message);
  }

  static void wtf(dynamic message) {
    to.wtf(message);
  }
}

// if u use a singleton instance 
// use with
// Log.i(...)