日志模块封封装:单例模式+策略模式+构建者模式+bugly

news/2024/10/18 2:35:20/

日志模块封装:单例模式+策略模式+构建者模式+bugly

  • 一.单例模式+策略模式+构建者模式
  • 二.日志模块封装
    • 1.日志等级:LoggerLevel枚举类
    • 2.日志输出策略:LoggerStrategy枚举类
    • 3.ILogger接口
    • 4.LogCatLogger/FileLogger/NetWorkLogger/EmailLogger
    • 5.使用构建者模式和策略模式创建对应的logger对象
    • 6.最后业务模块中使用:
  • 三.bugly的使用
    • 1.什么是Bugly
    • 2.集成Bugly
    • 3.如何创建Bugly产品
    • 4.面试问题难点:如果项目混淆后如何准确定位到错误的信息
      • 0.现象
      • (1)集成文档最后
      • (2)点击符号表配置最后
      • (3)下载

一.单例模式+策略模式+构建者模式

设计模式传送门

二.日志模块封装

在这里插入图片描述
默认情况下我们的日志只能打印输出,没有永久保存,这里我们的日志不仅能log输出还要能上传到网络,邮件或者本地存储,下面我们进行简单的封装,这里涉及到kotlin基础以及单例模式/策略模式/构建者模式
在这里插入图片描述

1.日志等级:LoggerLevel枚举类

/*** @Author : ytx* @Time : On 2023/5/21 15:23* @Description : LoggerLevel 日志等级*/
enum class LoggerLevel(var value: Int) {Verbose(1),Debug(2),Info(3),Warn(4),Error(5)
}

2.日志输出策略:LoggerStrategy枚举类


/*** @Author : ytx* @Time : On 2023/5/21 15:36* @Description : LoggerType 日志输出策略*/
enum class LoggerStrategy {LOGCAT,FILE,EMAIL,NET
}

3.ILogger接口

/*** @Author : ytx* @Time : On 2023/5/21 15:18* @Description : ILogger:所有logger顶层接口*/
interface ILogger {fun d(tag:String,log:String)fun v(tag:String,log:String)fun i(tag:String,log:String)fun w(tag:String,log:String)fun e(tag:String,log:String)/*** 是否Debug*/fun setDebug(isDeug:Boolean)/*** 默认TAG*/fun setLogTAG(TAG:String)/*** 默认日志等级*/fun setLoggerLevel(level:LoggerLevel)/*** Log存储位置,可以是本地路径 可以是网络路径 可以是Email地址*/fun setSaveUrl(url:String)
}

4.LogCatLogger/FileLogger/NetWorkLogger/EmailLogger

创建logger包,下面分别对应4种不同方式,以LogCatLogger为案例

/*** @Author : ytx* @Time : On 2023/5/21 15:26* @Description : LogcatLogger:打印输出log*/
class LogcatLogger: ILogger {private var isDebug = trueprivate var TAG = ""private var level = LoggerLevel.Debugprivate var loggerFormat = "(:=>$TAG %s -->%s"private var url = ""override fun d(tag: String, log: String) {if(isDebug && level.ordinal >= LoggerLevel.Debug.ordinal){Log.d(TAG,String.format(loggerFormat,tag,log))}}override fun v(tag: String, log: String) {if(isDebug && level.ordinal >= LoggerLevel.Verbose.ordinal){Log.v(TAG,String.format(loggerFormat,tag,log))}}override fun i(tag: String, log: String) {if(isDebug && level.ordinal >= LoggerLevel.Info.ordinal){Log.i(TAG,String.format(loggerFormat,tag,log))}}override fun w(tag: String, log: String) {if(isDebug && level.ordinal >= LoggerLevel.Warn.ordinal){Log.w(TAG,String.format(loggerFormat,tag,log))}}override fun e(tag: String, log: String) {if(isDebug && level.ordinal >= LoggerLevel.Error.ordinal){Log.e(TAG,String.format(loggerFormat,tag,log))}}override fun setDebug(isDebug: Boolean) {this.isDebug = isDebug}override fun setLogTAG(TAG: String) {this.TAG = TAG}override fun setLoggerLevel(level: LoggerLevel) {this.level = level}override fun setSaveUrl(url: String) {this.url = url}
}

5.使用构建者模式和策略模式创建对应的logger对象

/*** @Author : ytx* @Time : On 2023/5/21 15:37* @Description : Logger创建对应的logger对象 采用策略模式和构建者*/
class Logger private constructor (private val TAG:String, private val level:LoggerLevel, private val loggerType: LoggerStrategy, private val isDebug:Boolean, private val saveUrl:String) {private var logger:ILoggerinit {logger = getLogger()}constructor(builder: Builder):this(builder.TAG,builder.level,builder.loggerType,builder.isDebug,builder.saveUrl)/*** 创建Logger*/fun getLogger():ILogger{when(loggerType){LoggerStrategy.EMAIL -> throw IllegalArgumentException("该方案未实现")LoggerStrategy.FILE -> throw IllegalArgumentException("该方案未实现")LoggerStrategy.NET -> throw IllegalArgumentException("该方案未实现")LoggerStrategy.LOGCAT -> logger = LogcatLogger()}logger.setLoggerLevel(level)logger.setLogTAG(TAG)logger.setDebug(isDebug)logger.setSaveUrl(saveUrl)return logger}/*** 输出Debug log*/fun d(Tag:String,log:String){logger.d(Tag,log)}/*** 输出Warn log*/fun w(Tag:String,log:String){logger.w(Tag,log)}/*** 输出Verbose log*/fun v(Tag:String,log:String){logger.v(Tag,log)}/*** 输出Error log*/fun e(Tag:String,log:String){logger.e(Tag,log)}/*** 输出Info log*/fun i(Tag:String,log:String){logger.i(Tag,log)}class Builder{var TAG:String = "默认TAG"var level:LoggerLevel = LoggerLevel.Debugvar loggerType: LoggerStrategy = LoggerStrategy.LOGCATvar isDebug:Boolean = truevar saveUrl:String = "默认路径"fun setTAG(TAG:String):Builder{this.TAG = TAGreturn this}fun setLevel(level:LoggerLevel):Builder{this.level = levelreturn this}fun setLoggerType(loggerType: LoggerStrategy):Builder{//设置策略this.loggerType = loggerTypereturn this}fun isDebug(isDebug: Boolean):Builder{this.isDebug = isDebugreturn this}fun setSaveUrl(saveUrl: String):Builder{this.saveUrl = saveUrlreturn this}fun build():Logger{return Logger(this)}}}

6.最后业务模块中使用:

class LoggerUtils {companion object{private val logger = Logger.Builder().setLevel(LoggerLevel.Error).setLoggerType(LoggerStrategy.LOGCAT).isDebug(true).setTAG("main业务模块").build()fun d(tag:String,log:String){logger.d(tag,log)}}
}
LoggerUtils.d("123","234")

三.bugly的使用

1.什么是Bugly

腾讯Bugly,为移动开发者提供专业的异常上报和运营统计,帮助开发者快速发现并
解决异常,同时掌握产品运营动态,及时跟进用户反馈。

2.集成Bugly

https://bugly.qq.com/docs/user-guide/instruction-manual-android/?v=1.0.0

3.如何创建Bugly产品

https://bugly.qq.com/v2/workbench/apps

在这里插入图片描述

4.面试问题难点:如果项目混淆后如何准确定位到错误的信息

0.现象

class Utils {companion object{fun chu2( num1:Int, num2:Int):Int{return num1/num2}}
}
class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)//制造异常var result = Utils.chu2(4,0)}
}

设置代码混淆在这里插入图片描述
打包成apk,并将apk安装到手机上,报错,不显示Utils的第几行报错,因为Utils默认被混淆,而activity安卓的四大组件默认不被混淆,那么怎么解决这个问题呢
在这里插入图片描述

解决问题方案:

(1)集成文档最后

在这里插入图片描述

(2)点击符号表配置最后

在这里插入图片描述

(3)下载

在这里插入图片描述
a。将jar扔到根目录下,注意根目录不是libs
b。大家可以看文档的有关参数说明,我这边使用的命令是这样,以后可以方便复制使用
java -jar buglyqq-upload-symbol.jar -appid xxxx -appkey xxxxx -bundleid com.zhongjh -version 5.5.0 -platform Android -inputSymbol D:\XXX\build\outputs\mapping\debug\mapping.txt -inputMapping D:\XXX\build\outputs\mapping\debug\mapping.txt
然后回车,执行,看到200则表示上传成功
在这里插入图片描述
c。崩溃信息中可以看到报错的具体位置,即使代码混淆后
在这里插入图片描述


http://www.ppmy.cn/news/80317.html

相关文章

RocketMq源码分析(七)--消息发送流程

文章目录 一、消息发送入口二、消息发送流程1、消息验证1)消息主题验证2)消息内容验证 2、查找路由3、消息发送1)选择消息队列2)消息发送-内核实现sendKernelImpl方法参数获取brokerAddr添加消息全局唯一id设置实例id设置系统标记…

Rust每日一练(Leetday0010) 子串下标、两数相除、串联子串

目录 28. 找出字符串中第一个匹配项的下标 Find-the-index-of-the-first-occurrence-in-a-string 🌟🌟 29. 两数相除 Divide Two Integers 🌟🌟 30. 串联所有单词的子串 Substring-with-concatenation-of-all-words &#x…

Java常见Exception

运行时异常和非运行时异常 运行时异常:都是RuntimeException类及其子类异常: IndexOutOfBoundsException 索引越界异常ArithmeticException:数学计算异常NullPointerException:空指针异常ArrayOutOfBoundsException:数组索引越界异常ClassNotFoundExce…

Linux网络编程—Day10

Linux服务器程序规范 Linux服务器程序一般以后台进程形式运行。后台进程又称守护进程。它没有控制终端,因而也不会意外接收到用户输入。 守护进程的父进程通常是init进程(PID为1的进程);Linux服务器程序通常有一套日志系统&#…

黑客如何从零学起?

一、MYSQL5.7 MySQL是如今使用最多的数据库,是众多企业的首选,在未来几年都将被持续推动发展。 学习MySQL需注重实战操作,循序渐进地了解MySQL中的各项技术,这样才能在实际工作中的关键应用。 想进入网络安全行业, …

Systrace系列2 —— 预备知识

本文主要是讲解一些分析 Systrace 的预备知识, 主要baoku如何查看 Systrace 中的线程状态 , 如何对线程的唤醒信息进行分析, 如何解读信息区的数据, 以及介绍了常用的快捷键. 通过本篇文章的学习, 相信你可以掌握进程和线程相关的一些信息, 也知道如何查看复杂的 Systrace 中包…

从0到1无比流畅的React入门教程

无比流畅的React入门教程TOC React 是什么 简介 用于构建 Web 和原生交互界面的库React 用组件创建用户界面通俗来讲:是一个将数据渲染为HTML视图的开源JS库 其他信息 Facebook 开发,并且开源 为什么使用React? 原生JS使用DOM-API修改UI代码很繁…

文生图关键问题探索:个性化定制和效果评价

文生图(Text-to-Image Generation)是AIGC(AI Generated Content,人工智能生成内容)的一个主要方向。近年来,文生图模型的效果和质量得到飞速提升,投资界和研究界都在密切关注文生图模型的进展。…