UNPKG

react-native-logs

Version:

Performance-aware simple logger for React-Native with namespaces, custom levels and custom transports (colored console, file writing, etc.)

170 lines (150 loc) 4.05 kB
import { transportFunctionType } from "../index"; type RNFS = { DocumentDirectoryPath: string; documentDirectory: never; writeAsStringAsync: undefined; appendFile: ( filepath: string, contents: string, encoding?: string ) => Promise<void>; }; type EXPOFS = { documentDirectory: string | null; DocumentDirectoryPath: never; writeAsStringAsync: ( fileUri: string, contents: string, options?: object ) => Promise<void>; readAsStringAsync?: (fileUri: string, options?: object) => Promise<string>; getInfoAsync?: ( fileUri: string, options?: object ) => Promise<{ exists: boolean }>; appendFile: undefined; }; interface EXPOqueueitem { FS: Required<EXPOFS>; file: string; msg: string; } let EXPOqueue: Array<EXPOqueueitem> = []; let EXPOelaborate = false; const EXPOFSreadwrite = async () => { if (EXPOqueue.length === 0) return; EXPOelaborate = true; const item = EXPOqueue[0]; try { const prevFile = await item.FS.readAsStringAsync(item.file).catch(() => ""); const newMsg = prevFile + item.msg; await item.FS.writeAsStringAsync(item.file, newMsg); } catch (error) { console.error("Failed to write log to file:", error); } finally { EXPOelaborate = false; EXPOqueue.shift(); if (EXPOqueue.length > 0) { EXPOFSreadwrite().then(); } } }; const EXPOcheckqueue = async ( FS: Required<EXPOFS>, file: string, msg: string ) => { EXPOqueue.push({ FS, file, msg }); if (!EXPOelaborate) { await EXPOFSreadwrite(); } }; const EXPOFSappend = async ( FS: Required<EXPOFS>, file: string, msg: string ) => { try { const fileInfo = await FS.getInfoAsync(file); if (!fileInfo.exists) { await FS.writeAsStringAsync(file, msg); return true; } else { await EXPOcheckqueue(FS, file, msg); return true; } } catch (error) { console.error(error); return false; } }; const RNFSappend = async (FS: any, file: string, msg: string) => { try { await FS.appendFile(file, msg, "utf8"); return true; } catch (error) { console.error(error); return false; } }; const dateReplacer = (filename: string, type?: "eu" | "us" | "iso") => { let today = new Date(); let d = today.getDate(); let m = today.getMonth() + 1; let y = today.getFullYear(); switch (type) { case "eu": return filename.replace("{date-today}", `${d}-${m}-${y}`); case "us": return filename.replace("{date-today}", `${m}-${d}-${y}`); case "iso": return filename.replace("{date-today}", `${y}-${m}-${d}`); default: return filename.replace("{date-today}", `${d}-${m}-${y}`); } }; export interface FileAsyncTransportOptions { fileNameDateType?: "eu" | "us" | "iso"; FS: any; fileName?: string; filePath?: string; } const fileAsyncTransport: transportFunctionType<FileAsyncTransportOptions> = ( props ) => { if (!props) return false; let WRITE: (FS: any, file: string, msg: string) => Promise<boolean>; let fileName: string = "log"; let filePath: string; if (!props?.options?.FS) { throw Error( `react-native-logs: fileAsyncTransport - No FileSystem instance provided` ); } let FSF = props.options.FS as RNFS | EXPOFS; if (FSF.DocumentDirectoryPath && FSF.appendFile) { WRITE = RNFSappend; filePath = FSF.DocumentDirectoryPath; } else if ( FSF["documentDirectory"] && FSF["writeAsStringAsync"] && FSF["readAsStringAsync"] && FSF["getInfoAsync"] ) { WRITE = EXPOFSappend; filePath = FSF.documentDirectory; } else { throw Error( `react-native-logs: fileAsyncTransport - FileSystem not supported` ); } if (props?.options?.fileName) { fileName = props.options.fileName; fileName = dateReplacer(fileName, props.options?.fileNameDateType); } if (props?.options?.filePath) filePath = props.options.filePath; let output = `${props?.msg}\n`; var path = filePath + "/" + fileName; WRITE(FSF, path, output); }; export { fileAsyncTransport };