PAW 🐾

pub package CI Last Commits Pull Requests Code size License

Paw is a compact, well-organized, and user-friendly logging tool for your apps. It's designed to log your code's journey with structure and clarity, leaving a trace of each step like a paw print.

Installation

You can directly install it by adding paw: ^0.0.3 to your pubspec.yaml dependencies section or you can also add Paw 🐾 to your project by executing,

  • For Flutter Project - flutter pub add paw
  • For Dart Project - dart pub add paw

Getting Started

Integrate Paw into your Flutter projects in two distinct ways:

Paw

The Paw class offers a straightforward approach to logging in your project.

Simply instantiate the Paw class and utilize its various methods such as warn, info, debug, and error for logging. Consider the following example:

import 'package:paw/paw.dart';

void main() {
  // Create an instance of [Paw] with customized settings.
  final paw = Paw(
    title: "MyApp",
    shouldIncludeSourceFileInfo: true,
    shouldIncludeTitle: true,
    shouldPrint: true,
    stackTraceToPrint: 5,
  );

  // Log an informational message.
  paw.info("This is an informational message");

  // Log a warning message.
  paw.warn("Be aware! This is a warning message");

  // Log a debugging data object.
  paw.debug({'key': 'value', 'count': 42});

  // Log an error with additional context.
  try {
    throw UnsupportedError("Oops! You've forgotten to implement this feature");
  } catch (e, stackTrace) {
    // Log an error with a message, error object, and stack trace.
    paw.error(
      'An unexpected error occurred',
      stackTrace: stackTrace,
      error: e,
    );
  }
}

For more details on how to use Paw logger, have a look at this example.

To maintain consistency and avoid redundancy, it's not recommended to create a new instance of Paw for every class or function. More details here

PawInterface

PawInterface allows for more tailored control over the logging process in your applications. Implement your custom logger as follows:

import 'package:paw/paw.dart';

class CustomLogger extends PawInterface {
  CustomLogger({
    super.name = "MyApp",
    super.maxStackTraces = 5,
    super.shouldIncludeSourceInfo = false,
    super.shouldPrintLogs = true,
    super.shouldPrintName = true,
  });

  @override
  void info(String msg, {StackTrace? stackTrace}) {
    super.info(msg, stackTrace: stackTrace);

    // Add custom behavior when logging information.
    // Example: Integrate additional functionality such as crash reporting.
    print("Additional tasks after logging info");
  }
}

Similar to using Paw class, you can use your own CustomLogger in the same way, as fallowing,

void main() {
  // Instantiate your [CustomLogger].
  final logger = CustomLogger();

  // Log an informational message.
  logger.info("This is an informational message");

  // Log a warning message.
  logger.warn("Be aware! This is a warning message");

  // Log a debugging data object.
  logger.debug({'key': 'value', 'count': 42});

  // Log an error with additional context.
  try {
    throw UnsupportedError("Oops! You've forgotten to implement this feature");
  } catch (e, stackTrace) {
    // Log an error with a message, error object, and stack trace.
    logger.error(
      'An unexpected error occurred',
      stackTrace: stackTrace,
      error: e,
    );
  }
}

For guidance on implementing your CustomLogger, see this example.

Try to create global variable to access your CustomLogger or convert your CustomLogger into a singleton to avoid redundancy. More details here

Outputs

Paw provides clear and organized log outputs, making debugging and monitoring an easy task. Here's an example of what Paw's outputs look like:

Paw Showcase

Documentation

Below are various logging levels provided by Paw,

info

Log informational messages. Ideal for general app behaviors and states.

Paw().info('This is an informational message');

warn

Log warnings. Use this for non-critical issues that should be noted.

Paw().warn('This is a warning message');

debug

Log debugging information. Essential for troubleshooting and understanding complex flows.

Paw().debug({'key': 'value', 'count': 42});

error

Log errors with detailed information, including error objects and stack traces. Critical for error tracking.

try {
  // Code that might throw an error
} catch (e, stackTrace) {
  Paw().error('An unexpected error occurred', error: e, stackTrace: stackTrace);
}

Efficient Usage Practices

To maintain consistency and avoid redundancy, it's not recommended to create a new instance of Paw for every class or function. Doing so can lead to issues with maintaining standard configurations throughout your application.

For instance, if you decide to change a configuration, like hiding source file info or disabling log printing, modifying every Paw instance becomes impractical.

To address this, consider one of the following approaches:

Using a Global Instance

Creating a global instance of Paw helps avoid the creation of multiple instances with varying configurations. This approach promotes consistency and ease of configuration management.

import "package:paw/paw.dart";

// Global instance of [Paw] with custom configurations.
// This instance can be accessed throughout your application.
final paw = Paw(
  title: "MyApp",
  shouldIncludeSourceFileInfo: true,
  shouldIncludeTitle: true,
  shouldPrint: true,
  stackTraceToPrint: 5,
);

Implementing a Singleton CustomLogger

If global variables don't align with your project's architecture, or you prefer a more encapsulated approach, a singleton CustomLogger is a viable alternative.

import "package:paw/paw.dart";

///
/// Singleton [CustomLogger] class.
///
class CustomLogger extends PawInterface {
  // Private constructor to prevent external instantiation.
  CustomLogger._({
    required super.name,
    required super.maxStackTraces,
    required super.shouldIncludeSourceInfo,
    required super.shouldPrintLogs,
    required super.shouldPrintName,
  });

  // Static instance for external access.
  static CustomLogger? _instance;

  // Public factory constructor.
  factory CustomLogger() {
    // Initialize the instance if it hasn't been already.
    _instance ??= CustomLogger._(
      name: "MyApp",
      maxStackTraces: 5,
      shouldIncludeSourceInfo: true,
      shouldPrintLogs: true,
      shouldPrintName: true,
    );

    return _instance!;
  }

  @override
  void info(String msg, {StackTrace? stackTrace}) {
    super.info(msg, stackTrace: stackTrace);

    // Optional: Additional functionality after logging.
    print("Custom actions after logging info");
  }
}

Contributing

We welcome contributions! If you'd like to improve Paw, please open an issue or an PR with your suggested changes on this repo. Happy Coding 🐾!

Libraries

paw