mappls-map-react-native
Version:
A Mappls GL react native module for creating custom maps
131 lines (111 loc) • 3.52 kB
text/typescript
import { NativeEventEmitter, NativeModules, type EmitterSubscription, type EventSubscription } from "react-native";
import NativeRCTMGLLogging from "../../specs/NativeRCTMGLLogging";
const MGLLogging = NativeRCTMGLLogging == null ? Object.create(NativeModules.MGLLogging): NativeRCTMGLLogging;
export type LogLevel = "error" | "warning" | "info" | "debug" | "verbose";
interface Log {
message: string;
level: LogLevel;
tag?: string;
}
type LogCallback = (log: Log) => boolean;
export class Logger {
static instance: Logger | null = null;
static sharedInstance(): Logger {
if (this.instance === null) {
this.instance = new Logger();
}
return this.instance;
}
private loggerEmitter: NativeEventEmitter;
private startedCount: number;
private logCallback: LogCallback | null;
private subscription: EmitterSubscription | null | EventSubscription;
constructor() {
this.loggerEmitter = new NativeEventEmitter(MGLLogging);
this.startedCount = 0;
this.logCallback = null;
this.subscription = null;
}
/**
* Set custom logger function.
* @param {Logger~logCallback} logCallback - callback taking a log object as param. If callback return falsy value then
* default logging will take place.
*/
static setLogCallback(logCallback: LogCallback): void {
this.sharedInstance().setLogCallback(logCallback);
}
/**
* Set custom logger function.
* @param {Logger~logCallback} logCallback - callback taking a log object as param. If callback return falsy value then
* default logging will take place.
*/
setLogCallback(logCallback: LogCallback): void {
this.logCallback = logCallback;
}
/**
* This callback is displayed as part of the Requester class.
* @callback Logger~logCallback
* @param {object} log
* @param {string} log.message - the message of the log
* @param {string} log.level - log level
* @param {string} log.tag - optional tag used on android
*/
/**
* setLogLevel
* @param {LogLevel} level
*/
static setLogLevel(level: LogLevel): void {
MGLLogging.setLogLevel(level);
}
/**
* @type {('error'|'warning'|'info'|'debug'|'verbose')} LogLevel - Supported log levels
*/
start(): void {
if (this.startedCount === 0) {
this.subscribe();
}
this.startedCount += 1;
}
stop(): void {
this.startedCount -= 1;
if (this.startedCount === 0) {
this.unsubscribe();
}
}
subscribe(): void {
this.subscription = this.loggerEmitter.addListener("LogEvent", (log) => {
this.onLog(log);
});
}
unsubscribe(): void {
if (this.subscription) {
this.subscription.remove();
this.subscription = null;
}
}
effectiveLevel({ level, message, tag }: Log): LogLevel {
if (level === "warning") {
if (
tag === "Mbgl-HttpRequest" &&
message.startsWith("Request failed due to a permanent error: Canceled")
) {
// this seems to happening too much to show a warning every time
return "info";
}
}
return level;
}
onLog(log: Log): void {
if (!this.logCallback || !this.logCallback(log)) {
const { message } = log;
const level = this.effectiveLevel(log);
if (level === "error") {
console.error("Mappls error", message, log);
} else if (level === "warning") {
console.warn("Mappls warning", message, log);
} else {
console.log(`Mappls [${level}]`, message, log);
}
}
}
}