/* * This file is part of Stack Wallet. * * Copyright (c) 2023 Cypher Stack * All Rights Reserved. * The code is distributed under GPLv3 license, see LICENSE file for details. * Generated by Cypher Stack on 2023-05-26 * */ import 'dart:core' as core; import 'dart:core'; import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:isar/isar.dart'; import '../models/isar/models/log.dart'; import 'constants.dart'; import 'enums/log_level_enum.dart'; export 'enums/log_level_enum.dart'; class Logging { static const isArmLinux = bool.fromEnvironment("IS_ARM"); static final isTestEnv = Platform.environment["FLUTTER_TEST"] == "true"; Logging._(); static final Logging _instance = Logging._(); static Logging get instance => _instance; static const core.int defaultPrintLength = 1020; late final Isar? isar; late final _AsyncLogWriterQueue _queue; Future init(Isar isar) async { _queue = _AsyncLogWriterQueue(); this.isar = isar; } void log( core.Object? object, { required LogLevel level, core.bool printToConsole = true, core.bool printFullLength = false, }) { try { if (isTestEnv || isArmLinux) { Logger.print(object, normalLength: !printFullLength); return; } String message = object.toString(); // random value to check max size of message before storing in db if (message.length > 20000) { message = "${message.substring(0, 20000)}..."; } final now = core.DateTime.now().toUtc(); final log = Log() ..message = message ..logLevel = level ..timestampInMillisUTC = now.millisecondsSinceEpoch; if (level == LogLevel.Error || level == LogLevel.Fatal) { printFullLength = true; } _queue.add( () async => isar!.writeTxn( () async => await isar!.logs.put(log), ), ); if (printToConsole) { final core.String logStr = "Log: ${log.toString()}"; final core.int logLength = logStr.length; if (!printFullLength || logLength <= defaultPrintLength) { debugPrint(logStr); } else { core.int start = 0; core.int endIndex = defaultPrintLength; core.int tmpLogLength = logLength; while (endIndex < logLength) { debugPrint(logStr.substring(start, endIndex)); endIndex += defaultPrintLength; start += defaultPrintLength; tmpLogLength -= defaultPrintLength; } if (tmpLogLength > 0) { debugPrint(logStr.substring(start, logLength)); } } } } catch (e, s) { print("problem trying to log"); print("$e $s"); Logger.print(object); } } } abstract class Logger { static final isTestEnv = Platform.environment["FLUTTER_TEST"] == "true"; static void print( core.Object? object, { core.bool withTimeStamp = true, core.bool normalLength = true, }) async { if (Constants.disableLogger && !isTestEnv) { return; } final utcTime = withTimeStamp ? "${core.DateTime.now().toUtc()}: " : ""; final core.int defaultPrintLength = 1020 - utcTime.length; if (normalLength) { debugPrint("$utcTime$object"); } else if (object == null || object.toString().length <= defaultPrintLength) { debugPrint("$utcTime$object"); } else { final core.String log = object.toString(); core.int start = 0; core.int endIndex = defaultPrintLength; final core.int logLength = log.length; core.int tmpLogLength = log.length; while (endIndex < logLength) { debugPrint(utcTime + log.substring(start, endIndex)); endIndex += defaultPrintLength; start += defaultPrintLength; tmpLogLength -= defaultPrintLength; } if (tmpLogLength > 0) { debugPrint(utcTime + log.substring(start, logLength)); } } } } /// basic async queue for writing logs in the [Logging] to isar class _AsyncLogWriterQueue { final List Function()> _queue = []; bool _runningLock = false; void add(Future Function() futureFunction) { _queue.add(futureFunction); _run(); } void _run() async { if (_runningLock) { return; } _runningLock = true; try { while (_queue.isNotEmpty) { final futureFunction = _queue.removeAt(0); try { await futureFunction.call(); } catch (e, s) { debugPrint("$e\n$s"); } } } finally { _runningLock = false; } } }