PAW 🐾
Paw 🐾 is a logging tool that prioritizes accessibility and readability, while also offering highly customizable logs
Quick Links
Installation
You can directly install Paw 🐾 by adding paw: ^0.0.4
to your pubspec.yaml dependencies section
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
Getting started with Paw 🐾 is easy! You can integrate it into your project by fallowing ways:
Paw
The Paw
class offers a straightforward approach to logging in your project. Simply instantiate the Paw
class and utilize its various methods for logging. Have a look at example below,
import 'package:paw/paw.dart';
///
/// Create an instance of [paw] with custom configurations.
///
final paw = Paw(
// optional, defaults to [PAW]
title: "MyApp",
// optional, defaults to [true]
shouldIncludeSourceFileInfo: true,
// optional, defaults to [true]
shouldIncludeTitle: true,
// optional, defaults to [true]
shouldPrint: true,
// optional, defaults to [5]
stackTraceToPrint: 5,
// optional, defaults to [PawDarkTheme]
theme: PawDarkTheme(),
// Note: When the `level` is set to [null], Paw is allowed to print logs
// of all levels. To only print logs of a certain level, set the `level` to
// that specific level, e.g. [PawLogLevels.fetal] to only print fetal logs
level: null, // this allows paw to print all the logs, defaults to [null]
);
For more details on how to use Paw
class, have a look at this example.
👉 NOTE: 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 control over the logging process in Paw 🐾. You can implement your custom logger as fallows:
import 'package:paw/paw.dart';
///
/// [MyLogger] is a custom logger class created with [PawInterface] to help
/// enhance the functionality of Paw 🐾
///
class MyLogger extends PawInterface {
///
/// All the fields are optional, you can edit them according to your needs
///
MyLogger({
super.name = "MyApp",
super.maxStackTraces = 5,
super.shouldIncludeSourceInfo = false,
super.shouldPrintLogs = true,
super.shouldPrintName = false,
}) : super(
currentTheme: PawDarkTheme(),
);
///
/// You can override all the log levels to enhance their functionality
///
@override
void info(String msg, {StackTrace? stackTrace}) {
super.info(msg, stackTrace: stackTrace);
// Optional: Additional functionality after logging.
print("Custom actions after logging info");
}
//
// You can override any log level to enhance its functionality
//
}
Similar to using Paw
class, you can use MyLogger
in the same way. For more details, have a look at this
example.
👉 NOTE: Try to create global variable to access
MyLogger
or convertMyLogger
into a singleton to avoid redundancy. More details here
Log Levels
Below are various logging levels provided by Paw
,
info
Log an informational message. Use this for general app flow information, which could be helpful for understanding the app's behavior.
///
/// Log an informational message.
///
/// Use this for general app flow information, which could be helpful for
/// understanding the app's behavior.
///
paw.info("This is an informational message");
trace
Log a tracing message. Use this for tracking code flow and high-volume logs
///
/// Log a tracing message
///
/// Use this for tracking code flow and high-volume logs
///
paw.trace("This is a trace log");
warn
Log a warning message. Use this for non-critical issues that should be noted.
///
/// Log a warning message.
///
/// Warn logs are useful for non-critical issues that should be
/// brought to attention.
///
paw.warn("Be aware! This is a warning message");
debug
Log a data object for debugging. Essential for troubleshooting and understanding complex data objects in your code.
///
/// Log a data object for debugging.
///
/// This is particularly useful for logging structured data, making it
/// easier to understand complex data states.
///
paw.debug({'key': 'value', 'count': 42});
error
Log an error with additional context. Use this for logging exceptions or errors that occur in your application.
///
/// Log an error with additional context.
///
/// Here you can pass a message, an error object for in-depth debugging.
///
/// Use this for logging exceptions or errors that occur in your application.
///
try {
throw UnsupportedError("Oops! You've forgotten to implement this feature");
} catch (e) {
// Log an error with a message and error object
paw.error(
'An unexpected error occurred',
error: e,
);
}
fetal
Log an error with additional context such as a message, an error object, and even a stack trace for in-depth debugging. Use this for logging critical exceptions or errors that may break your application.
///
/// Log an error with additional context.
///
/// Here you can pass a message, an error object, and even a stack trace
/// for in-depth debugging.
///
/// Use this for logging exceptions or errors that occur in your application.
///
try {
throw UnsupportedError("Oops! You've forgotten to implement this feature");
} catch (e, stackTrace) {
// Log a fetal log with a message, error object, and stack trace
paw.fetal(
'A very serious error occurred',
stackTrace: stackTrace,
error: e,
);
}
Themes
To increase accessability and readability of the logs, Paw 🐾 provides two themes out of the box,
PawDarkTheme
PawDarkTheme
is suitable option when your device or code editor has a dark theme. Look at the
example below to use PawDarkTheme
,
import 'package:paw/paw.dart';
///
/// Create an instance of [Paw] with [PawDarkTheme]
///
final paw = Paw(
theme: PawDarkTheme(),
);
PawLightTheme
PawLightTheme
is suitable option when your device or code editor has a light theme. Look at the
example below to use PawLightTheme
,
import 'package:paw/paw.dart';
///
/// Create an instance of [Paw] with [PawLightTheme]
///
final paw = Paw(
theme: PawLightTheme(),
);
Custom Themes
To customise colors of the logs, you can create your own theme by using PawCustomTheme
class.
Paw provides various ANSI colors out of the box to help you create your themes, you can use AnsiForegroundColors
and
AnsiBackgroundColor
respectively to create your themes. You can also bring your own colors to your theme by using the
available custom
function on both of the colors classes.
Look at the example below to create your own custom theme,
import 'package:paw/paw.dart';
///
/// Custom theme created using [PawCustomTheme] to customise colors of the logs
/// printed on the consol with [Paw]
///
final kCustomTheme = PawCustomTheme(
heading: AnsiForegroundColors.black,
message: AnsiForegroundColors.softPink,
object: AnsiForegroundColors.gray,
errorMessage: AnsiForegroundColors.orange,
errorObject: AnsiForegroundColors.red,
bgWarn: AnsiBackgroundColor.lightGray,
bgInfo: AnsiBackgroundColor.blue,
bgTrace: AnsiBackgroundColor.darkPink,
bgDebug: AnsiBackgroundColor.gray,
bgError: AnsiBackgroundColor.darkPink,
bgFetal: AnsiBackgroundColor.brown,
infoCardBg: AnsiBackgroundColor.custom(r: 204, g: 255, b: 153),
);
///
/// Create an instance of [Paw] with [kCustomTheme]
///
final paw = Paw(
theme: kCustomTheme,
);
For more details on how to create and use your custom themes, have a look at this example.
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';
///
/// Create a global immutable / constant instance of [Paw] with custom configurations.
///
final kPaw = Paw(
// optional, defaults to [PAW]
title: "MyApp",
// optional, defaults to [true]
shouldIncludeSourceFileInfo: true,
// optional, defaults to [true]
shouldIncludeTitle: true,
// optional, defaults to [true]
shouldPrint: true,
// optional, defaults to [5]
stackTraceToPrint: 5,
// optional, defaults to [PawDarkTheme]
theme: PawDarkTheme(),
// Note: When the `level` is set to [null], Paw is allowed to print logs
// of all levels. To only print logs of a certain level, set the `level` to
// that specific level, e.g. [PawLogLevels.fetal] to only print fetal logs
level: null, // this allows paw to print all the logs, defaults to [null]
);
Implementing a Singleton PawInterface
If global variables don't align with your project's architecture, or you prefer a more encapsulated approach,
a singleton implementation of PawInterface
is a viable alternative.
import "package:paw/paw.dart";
///
/// Singleton [MyLogger] class.
///
class MyLogger extends PawInterface {
// Private constructor to prevent external instantiation.
MyLogger._({
required super.name,
required super.maxStackTraces,
required super.shouldIncludeSourceInfo,
required super.shouldPrintLogs,
required super.shouldPrintName,
required super.theme,
required super.level,
});
// Static instance for external access.
static MyLogger? _instance;
// Public factory constructor.
factory MyLogger() {
// Initialize the instance if it hasn't been already.
_instance ??= MyLogger._(
name: "MyApp",
maxStackTraces: 5,
shouldIncludeSourceInfo: true,
shouldPrintLogs: true,
shouldPrintName: true,
theme: PawDarkTheme(),
level: null,
);
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 in this repo. Happy Coding 🤝!