Logging Library
Logging library
Dependencies
- Log depends EnvironmentConfig.
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.
Cloud logging services
- As of now we have implemented Sentry to log and measure performance. Any other service is not available yet. To setup Sentry please check this.
- You can check out more details about it here: Sentry and Performance
- Also to enable sentry; developer will have to pass
sentryConfig
in environment.
- So developer should never use individual service in their application, they should always use Logging library for logging any kind of content.
- To setup Sentry please check this.
Use cases
use cases
- To easily log content on cloud
- To easily add another cloud logging service
- To log transactions. e.g. I want to measure and log time of an api call
- To see formatted (prettier) objects in the console easily readable by the human eye
- To easily differentiate between different kinds of events.
Log types
Currently, our logs are of six types.
- log
- info
- success
- warning
- exception
- 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:
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
andenableCloudLogs
, the content is logged. e.g. ifenableLocalLogs
in the environment is set tofalse
then no local logs will be printed. ifenableCloudLogs
is set tofalse
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;
}
}
}
}