Logging Library

Logging library

Overview

  • This is the central logging library which handles cloud (e.g. sentry, crashanalytics) and local (e.g. Console/Terminal and Local Files For Device) Logs.
  • So developer should never use individual service in their application, they should always use Logging library for logging any kind of content.
hierarchy
  • To setup Sentry please check this.

Use cases

Log types

Currently, our logs are of six types.

  1. log
  2. info
  3. success
  4. warning
  5. exception
  6. transaction

For Local Logs: Different types will print logs in different colors. the log will be in grey, info in blue, success in green, warning in yellow, and exception will be in red.

How to use

Call static methods of the Log class to log the events.

Log.log("Log");
Log.info("info");
Log.success("success");
Log.warning("warning");
try {
  // code snippet
} catch (error, stackTrace){
  Log.exception(error, stackTrace: stackTrace);
}

Log Transactions

When developer wants to measure performance of different operations they can use logTransaction funtion. Where developer will have to pass operation for which they wants to log as execute argument. e.g. API send receive requests, getting a file from local storage and parsing data, processing huge data, search queries, etc.

Log.logTransaction(
  execute: () async => {},
  details: const TransactionDetails(
    name: 'idle transaction',
    operation: 'idle',
  ),
);
Log.logTransaction(
  execute: Api.ajax('api.vaah.dev'),
  details: const TransactionDetails(
    name: 'get root route of vaah api',
    operation: 'read',
  ),
);

To print data, as argument pass the data

Map<String, dynamic> data = {
  "first_key": "value",
  "second_key": [
    {"key": "value"},
    {"key": "updated_value"},
  ],
};
Log.info('data', data: data);

Output:

Output

You can disable local and cloud logging for specific log

Log.exception('exception', disableLocalLogging: true);
Log.info('log', disableCloudLogging: true);

For exception you can pass two extra parameters: stackTrace and hint

catch (error, stackTrace){
    Log.exception(
        error,
        stackTrace: stackTrace,
        hint: 'The exception is caught in ---',
    )
}

How to add new cloud service?

Step 1: create a service which implements
LoggingService, example of implemented service: Sentry

Step 2: Add that service in _services array, in
logging_library.dart

  static final List<Type> _services = [
    SentryLoggingService,
    FirebaseLoggingService,
  ];

Step 3: Call relavent functions of that new service in _logEvent and exception,
switch cases

static void _logEvent(
    String text, {
    Object? data,
    EventType? type,
  }) {
    for (var service in _services) {
      switch (service) {
        case SentryLoggingService:
          SentryLoggingService.logEvent(
            message: text,
            level: type?.toSentryLevel,
            data: data,
          );
          return;
        case FirebaseLoggingService:
          FirebaseLoggingService.logEvent(
            message: text,
            type: type,
            data: data,
          );
          return;
        default:
          return;
      }
    }
  }
static void exception(
    dynamic throwable, {
    Object? data,
    dynamic stackTrace,
    dynamic hint,
    bool disableLocalLogging = false,
    bool disableCloudLogging = false,
  }) {
    EnvironmentConfig config = EnvironmentConfig.getEnvConfig();
    if (config.enableLocalLogs && !disableLocalLogging) {
      Console.danger(throwable.toString(), data);
    }
    if (config.enableCloudLogs && !disableCloudLogging) {
      final hintWithData = {
        'hint': hint,
        'data': data,
      };
      for (var service in _services) {
        switch (service) {
          case SentryLoggingService:
            SentryLoggingService.logException(
              throwable,
              stackTrace: stackTrace,
              hint: hintWithData,
            );
            return;
          case FirebaseLoggingService:
            FirebaseLoggingService.logException(
              throwable,
              stackTrace: stackTrace,
              hint: hintWithData,
            );
            return;
          default:
            return;
        }
      }
    }
  }

Enviroment variables which control logging

  • depending on environment variables enableLocalLogs and enableCloudLogs, the content is logged. e.g. if enableLocalLogs in the environment is set to false then no local logs will be printed. if enableCloudLogs is set to false then no local logs will be printed.

logging_library.dart Source code:

import './_cloud/firebase_logging_service.dart';
import './_cloud/logging_service.dart';
import './_cloud/sentry_logging_service.dart';
import './_local/console_service.dart';
import '../../env.dart';

class Log {
  static final List<Type> _services = [
    SentryLoggingService,
    // FirebaseLoggingService,
  ];

  static void log(
    dynamic text, {
    Object? data,
    bool disableLocalLogging = false,
    bool disableCloudLogging = false,
  }) {
    EnvironmentConfig config = EnvironmentConfig.getEnvConfig();
    if (config.enableLocalLogs && !disableLocalLogging) {
      Console.log(text.toString(), data);
    }
    if (config.enableCloudLogs && !disableCloudLogging) {
      _logEvent(text.toString(), data: data, type: EventType.log);
    }
  }

  static void info(
    dynamic text, {
    Object? data,
    bool disableLocalLogging = false,
    bool disableCloudLogging = false,
  }) {
    EnvironmentConfig config = EnvironmentConfig.getEnvConfig();
    if (config.enableLocalLogs && !disableLocalLogging) {
      Console.info(text.toString(), data);
    }
    if (config.enableCloudLogs && !disableCloudLogging) {
      _logEvent(text.toString(), data: data, type: EventType.info);
    }
  }

  static void success(
    dynamic text, {
    Object? data,
    bool disableLocalLogging = false,
    bool disableCloudLogging = false,
  }) {
    EnvironmentConfig config = EnvironmentConfig.getEnvConfig();
    if (config.enableLocalLogs && !disableLocalLogging) {
      Console.success(text.toString(), data);
    }
    if (config.enableCloudLogs && !disableCloudLogging) {
      _logEvent(text.toString(), data: data, type: EventType.success);
    }
  }

  static void warning(
    dynamic text, {
    Object? data,
    bool disableLocalLogging = false,
    bool disableCloudLogging = false,
  }) {
    EnvironmentConfig config = EnvironmentConfig.getEnvConfig();
    if (config.enableLocalLogs && !disableLocalLogging) {
      Console.warning(text.toString(), data);
    }
    if (config.enableCloudLogs && !disableCloudLogging) {
      _logEvent(text.toString(), data: data, type: EventType.warning);
    }
  }

  static void exception(
    dynamic throwable, {
    Object? data,
    dynamic stackTrace,
    dynamic hint,
    bool disableLocalLogging = false,
    bool disableCloudLogging = false,
  }) {
    EnvironmentConfig config = EnvironmentConfig.getEnvConfig();
    if (config.enableLocalLogs && !disableLocalLogging) {
      Console.danger(throwable.toString(), data);
    }
    if (config.enableCloudLogs && !disableCloudLogging) {
      final hintWithData = {
        'hint': hint,
        'data': data,
      };
      for (var service in _services) {
        switch (service) {
          case SentryLoggingService:
            SentryLoggingService.logException(
              throwable,
              stackTrace: stackTrace,
              hint: hintWithData,
            );
            return;
          case FirebaseLoggingService:
            FirebaseLoggingService.logException(
              throwable,
              stackTrace: stackTrace,
              hint: hintWithData,
            );
            return;
          default:
            return;
        }
      }
    }
  }

  static void _logEvent(
    String text, {
    Object? data,
    EventType? type,
  }) {
    for (var service in _services) {
      switch (service) {
        case SentryLoggingService:
          SentryLoggingService.logEvent(
            message: text,
            level: type?.toSentryLevel,
            data: data,
          );
          return;
        case FirebaseLoggingService:
          FirebaseLoggingService.logEvent(
            message: text,
            type: type,
            data: data,
          );
          return;
        default:
          return;
      }
    }
  }
}

Copyright © 2024