本文将带您了解关于如何在swift-log消息中自动包含源?的新内容,同时我们还将为您解释swift自定义cell的相关知识,另外,我们还将为您提供关于3000帧动画图解MySQL为什么需要binlo
本文将带您了解关于如何在 swift-log 消息中自动包含源?的新内容,同时我们还将为您解释swift 自定义cell的相关知识,另外,我们还将为您提供关于3000 帧动画图解 MySQL 为什么需要 binlog、redo log 和 undo log、7 mysql事务(包括redo log,undo log,MVCC)及事务实现原理、Android Log.v()、Log.d()、Log.i()、Log.w()、Log.e() - 什么时候使用它们?、Android Log.v(),Log.d(),Log.i(),Log.w(),Log.e() - 何时使用每一个?的实用信息。
本文目录一览:- 如何在 swift-log 消息中自动包含源?(swift 自定义cell)
- 3000 帧动画图解 MySQL 为什么需要 binlog、redo log 和 undo log
- 7 mysql事务(包括redo log,undo log,MVCC)及事务实现原理
- Android Log.v()、Log.d()、Log.i()、Log.w()、Log.e() - 什么时候使用它们?
- Android Log.v(),Log.d(),Log.i(),Log.w(),Log.e() - 何时使用每一个?
如何在 swift-log 消息中自动包含源?(swift 自定义cell)
如何解决如何在 swift-log 消息中自动包含源?
我正在使用 swift-log。我注意到 Logger 类在创建日志时包含一些额外的信息
debug(_ message: @autoclosure () -> Logger.Message,Metadata: @autoclosure () -> Logger.Metadata? = nil,source: @autoclosure () -> String? = nil,file: String = #file,function: String = #function,line: UInt = #line)
我可以轻松地将源名称包含在日志字符串中自己`"(Self.self) - 需要记录的内容",但我希望避免这种情况。
有没有办法让日志消息自动包含 source
或 file
或 line
?
当我在 XCTestCase 中使用此登录时
func testLogging() {
Logger.default.debug("Something to log")
}
我看到这个输出:
2021-02-26T08:42:10-0800 debug com.apple.dt.xctest.tool : Something to log
我希望看到测试类名称、函数和行号。
解决方法
记录器支持元数据。我添加了这个辅助函数来帮助添加测试名称:
extension Logger {
public mutating func setTestName(_ testName: String) {
//-[TestClass testName]
let parts = testName.replacingOccurrences(of: "-[",with: "")
.replacingOccurrences(of: "]",with: "")
.components(separatedBy: " ")
guard let testClass = parts.first,let testName = parts.last,testClass != testName,NSClassFromString("XCTestCase") != nil
else { return }
self[metadataKey: "test"] = "\\(testClass).\\(testName)"
}
// I also use the default Logger that I use for logging
public static var `default` = Logger.init(label: Bundle.main.bundleIdentifier ?? "DefaultLogger")
}
然后在我的测试中,我只是在设置中调用它:
override func setUp() {
Logger.default.setTestName(self.name)
}
我的日志来自:
2021-02-28T08:27:53-0800 debug com.apple.dt.xctest.tool : !!! Logging debug details
进入这个
2021-02-28T08:29:05-0800 debug com.apple.dt.xctest.tool : test=LogKitTests.testExample !!! Logging debug details
3000 帧动画图解 MySQL 为什么需要 binlog、redo log 和 undo log
全文建立在 MySQL 的存储引擎为 InnoDB 的基础上
先看一条 SQL 如何入库的:
这是一条很简单的更新 SQL,从 MySQL 服务端接收到 SQL 到落盘,先后经过了 MySQL Server 层和 InnoDB 存储引擎。
- Server 层就像一个产品经理,分析客户的需求,并给出实现需求的方案。
- InnoDB 就像一个基层程序员,实现产品经理给出的具体方案。
在 MySQL” 分析需求,实现方案 “的过程中,还夹杂着内存操作和磁盘操作,以及记录各种日志。
他们到底有什么用处?他们之间到底怎么配合的?MySQL 又为什么要分层呢?InnoDB 里面的那一块 Buffer Pool 又是什么?
我们慢慢分析。
分层结构
MySQL 为什么要分为 Server 层和存储引擎两层呢?
这个问题官方也没有给出明确的答案,但是也不难猜,简单来说就是为了 “解耦”。
Server 层和存储引擎各司其职,分工明确,用户可以根据不同的需求去使用合适的存储引擎,多好的设计,对不对?
后来的发展也验证了 “分层设计” 的优越性:MySQL 最初搭载的存储引擎是自研的只支持简单查询的 MyISAM 的前身 ISAM,后来与 Sleepycat 合作研发了 Berkeley DB 引擎,支持了事务。江山代有才人出,技术后浪推前浪,MySQL 在持续的升级着自己的存储引擎的过程中,遇到了横空出世的 InnoDB,InnoDB 的功能强大让 MySQL 倍感压力。
自己的存储引擎打不过 InnoDB 怎么办?
打不过就加入!
MySQL 选择了和 InnoDB 合作。正是因为 MySQL 存储引擎的插件化设计,两个公司合作的非常顺利,MySQL 也在合作后不久就发布了正式支持 nnoDB 的 4.0 版本以及经典的 4.1 版本。
MySQL 兼并天下模式也成为 MySQL 走向繁荣的一个重要因素。这能让 MySQL 长久地保持着极强竞争力。时至今日,MySQL 依然占据着极高数据库市场份额,仅次于王牌数据库 Oracle。
Buffer Pool
在 InnoDB 里,有一块非常重要的结构 ——Buffer Pool。
Buffer Pool 是个什么东西呢?
Buffer Pool 就是一块用于缓存 MySQL 磁盘数据的内存空间。
为什么要缓存 MySQL 磁盘数据呢?
我们通过一个例子说明,我们先假设没有 Buffer Pool,user 表里面只有一条记录,记录的 age = 1,假设需要执行三条 SQL:
- 事务 A:update user set age = 2
- 事务 B:update user set age = 3
- 事务 C:update user set age = 4
如果没有 Buffer Pool,那执行就是这样的:
从图上可以看出,每次更新都需要从磁盘拿数据(1 次 IO),修改完了需要刷到磁盘(1 次 IO),也就是每次更新都需要 2 次磁盘 IO。三次更新需要 6 次磁盘 IO。
而有了 Buffer Pool,执行就成了这样:
从图上可以看出,只需要在第一次执行的时候将数据从磁盘拿到 Buffer Pool(1 次 IO),第三次执行完将数据刷回磁盘(1 次 IO),整个过程只需要 2 次磁盘 IO,比没有 Buffer Pool 节省了 4 次磁盘 IO 的时间。
当然,Buffer Pool 真正的运转流程没有这么简单,具体实现细节和优化技巧还有很多,由于篇幅有限,本文不做详细描述。
我想表达的是:Buffer Pool 就是将磁盘 IO 转换成了内存操作,节省了时间,提高了效率。
Buffer Pool 是提高了效率没错,但是出现了一个问题,Buffer Pool 是基于内存的,而只要一断电,内存里面的数据就会全部丢失。
如果断电的时候 Buffer Pool 的数据还没来得及刷到磁盘,那么这些数据就丢失了吗?
还是上面的那个例子,如果三个事务执行完毕,在 age = 4 还没有刷到磁盘的时候,突然断电,数据就全部丢掉了:
试想一下,如果这些丢失的数据是核心的用户交易数据,那用户能接受吗?
答案是否定的。
那 InnoDB 是如何做到数据不会丢失的呢?
今天的第一个日志 ——redo log 登场了。
恢复 - redo log
顾名思义,redo 是重做的意思,redo log 就是重做日志的意思。
redo log 是如何保证数据不会丢失的呢?
就是在修改之后,先将修改后的值记录到磁盘上的 redo log 中,就算突然断电了,Buffer Pool 中的数据全部丢失了,来电的时候也可以根据 redo log 恢复 Buffer Pool,这样既利用到了 Buffer Pool 的内存高效性,也保证了数据不会丢失。
我们通过一个例子说明,我们先假设没有 Buffer Pool,user 表里面只有一条记录,记录的 age = 1,假设需要执行一条 SQL:
- 事务 A:update user set age = 2
执行过程如下:
如上图,有了 redo log 之后,将 age 修改成 2 之后,马上将 age = 2 写到 redo log 里面,如果这个时候突然断电内存数据丢失,在来电的时候,可以将 redo log 里面的数据读出来恢复数据,用这样的方式保证了数据不会丢失。
你可能会问,redo log 文件也在磁盘上,数据文件也在磁盘上,都是磁盘操作,何必多此一举?为什么不直接将修改的数据写到数据文件里面去呢?
傻瓜,因为 redo log 是磁盘顺序写,数据刷盘是磁盘随机写,磁盘的顺序写比随机写高效的多啊。
这种先预写日志后面再将数据刷盘的机制,有一个高大上的专业名词 ——WAL(Write-ahead logging),翻译成中文就是预写式日志。
虽然磁盘顺序写已经很高效了,但是和内存操作还是有一定的差距。
那么,有没有办法进一步优化一下呢?
答案是可以。那就是给 redo log 也加一个内存 buffer,也就是 redo log buffer,用这种套娃式的方法进一步提高效率。
redo log buffer 具体是怎么配合刷盘呢?
在这个问题之前之前,我们先来捋一下 MySQL 服务端和操作系统的关系:
MySQL 服务端是一个进程,它运行于操作系统之上。也就是说,操作系统挂了 MySQL 一定挂了,但是 MySQL 挂了操作系统不一定挂。
所以 MySQL 挂了有两种情况:
- MySQL 挂了,操作系统也挂了,也就是常说的服务器宕机了。这种情况 Buffer Pool 里面的数据会全部丢失,操作系统的 os cache 里面的数据也会丢失。
- MySQL 挂了,操作系统没有挂。这种情况 Buffer Pool 里面的数据会全部丢失,操作系统的 os cache 里面的数据不会丢失。
OK,了解了 MySQL 服务端和操作系统的关系之后,再来看 redo log 的落盘机制。redo log 的刷盘机制由参数 innodb_flush_log_at_trx_commit 控制,这个参数有 3 个值可以设置:
- innodb_flush_log_at_trx_commit = 1:实时写,实时刷
- innodb_flush_log_at_trx_commit = 0:延迟写,延迟刷
- innodb_flush_log_at_trx_commit = 2:实时写,延迟刷
写可以理解成写到操作系统的缓存(os cache),刷可以理解成把操作系统里面的缓存刷到磁盘。
这三种策略的区别,我们分开讨论:
innodb_flush_log_at_trx_commit = 1:实时写,实时刷
这种策略会在每次事务提交之前,每次都会将数据从 redo log 刷到磁盘中去,理论上只要磁盘不出问题,数据就不会丢失。
总结来说,这种策略效率最低,但是丢数据风险也最低。
innodb_flush_log_at_trx_commit = 0:延迟写,延迟刷
这种策略在事务提交时,只会把数据写到 redo log buffer 中,然后让后台线程定时去将 redo log buffer 里面的数据刷到磁盘。
这种策略是最高效的,但是我们都知道,定时任务是有间隙的,但是如果事务提交后,后台线程没来得及将 redo log 刷到磁盘,这个时候不管是 MySQL 进程挂了还是操作系统挂了,这一部分数据都会丢失。
总结来说这种策略效率最高,丢数据的风险也最高。
innodb_flush_log_at_trx_commit = 2:实时写,延迟刷
这种策略在事务提交之前会把 redo log 写到 os cache 中,但并不会实时地将 redo log 刷到磁盘,而是会每秒执行一次刷新磁盘操作。
这种情况下如果 MySQL 进程挂了,操作系统没挂的话,操作系统还是会将 os cache 刷到磁盘,数据不会丢失,如下图:
但如果 MySQL 所在的服务器挂掉了,也就是操作系统都挂了,那么 os cache 也会被清空,数据还是会丢失。如下图:
所以,这种 redo log 刷盘策略是上面两种策略的折中策略,效率比较高,丢失数据的风险比较低,绝大多情况下都推荐这种策略。
总结一下,redo log 的作用是用于恢复数据,写 redo log 的过程是磁盘顺序写,有三种刷盘策略,有 innodb_flush_log_at_trx_commit 参数控制,推荐设置成 2。
回滚 - undo log
我们都知道,InnoDB 是支持事务的,而事务是可以回滚的。
假如一个事务将 age=1 修改成了 age=2,在事务还没有提交的时候,后台线程已经将 age=2 刷入了磁盘。这个时候,不管是内存还是磁盘上,age 都变成了 2,如果事务要回滚,找不到修改之前的 age=1,无法回滚了。
那怎么办呢?
很简单,把修改之前的 age=1 存起来,回滚的时候根据存起来的 age=1 回滚就行了。
MySQL 确实是这么干的!这个记录修改之前的数据的过程,叫做记录 undo log。undo 翻译成中文是撤销、回滚的意思,undo log 的主要作用也就是回滚数据。
如何回滚呢?看下面这个图:
MySQL 在将 age = 1 修改成 age = 2 之前,先将 age = 1 存到 undo log 里面去,这样需要回滚的时候,可以将 undo log 里面的 age = 1 读出来回滚。
需要注意的是,undo log 默认存在全局表空间里面,你可以简单的理解成 undo log 也是记录在一个 MySQL 的表里面,插入一条 undo log 和插入一条普通数据是类似。也就是说,写 undo log 的过程中同样也是要写入 redo log 的。
归档 - binlog
undo log 记录的是修改之前的数据,提供回滚的能力。
redo log 记录的是修改之后的数据,提供了崩溃恢复的能力。
那 binlog 是干什么的呢?
binlog 记录的是修改之后的数据,用于归档。
和 redo log 日志类似,binlog 也有着自己的刷盘策略,通过 sync_binlog 参数控制:
- sync_binlog = 0 :每次提交事务前将 binlog 写入 os cache,由操作系统控制什么时候刷到磁盘
- sync_binlog =1 :采用同步写磁盘的方式来写 binlog,不使用 os cache 来写 binlog
- sync_binlog = N :当每进行 n 次事务提交之后,调用一次 fsync 将 os cache 中的 binlog 强制刷到磁盘
那么问题来了,binlog 和 redo log 都是记录的修改之后的值,这两者有什么区别呢?有 redo log 为什么还需要 binlog 呢?
首先看两者的一些区别:
- binlog 是逻辑日志,记录的是对哪一个表的哪一行做了什么修改;redo log 是物理日志,记录的是对哪个数据页中的哪个记录做了什么修改,如果你还不了解数据页,你可以理解成对磁盘上的哪个数据做了修改。
- binlog 是追加写;redo log 是循环写,日志文件有固定大小,会覆盖之前的数据。
- binlog 是 Server 层的日志;redo log 是 InnoDB 的日志。如果不使用 InnoDB 引擎,是没有 redo log 的。
但说实话,我觉得这些区别并不是 redo log 不能取代 binlog 的原因,MySQL 官方完全可以调整 redo log 让他兼并 binlog 的能力,但他没有这么做,为什么呢?
我认为不用 redo log 取代 binlog 最大的原因是 “没必要”。
为什么这么说呢?
第一点,binlog 的生态已经建立起来。MySQL 高可用主要就是依赖 binlog 复制,还有很多公司的数据分析系统和数据处理系统,也都是依赖的 binlog。取代 binlog 去改变一个生态费力了不讨好。
第二点,binlog 并不是 MySQL 的瓶颈,花时间在没有瓶颈的地方没必要。
总结
总结一下:
- Buffer Pool 是 MySQL 进程管理的一块内存空间,有减少磁盘 IO 次数的作用。
- redo log 是 InnoDB 存储引擎的一种日志,主要作用是崩溃恢复,有三种刷盘策略,有 innodb_flush_log_at_trx_commit 参数控制,推荐设置成 2。
- undo log 是 InnoDB 存储引擎的一种日志,主要作用是回滚。
- binlog 是 MySQL Server 层的一种日志,主要作用是归档。
- MySQL 挂了有两种情况:操作系统挂了 MySQL 进程跟着挂了;操作系统没挂,但是 MySQL 进程挂了。
最后,再用一张图总结一下全文的知识点:
7 mysql事务(包括redo log,undo log,MVCC)及事务实现原理
之前写了几篇mysql存储原理的文章。
6 Innodb_buffer_pool
5 b+ tree和每个page存储结构
4 innodb文件系统基本结构(段、簇、页面)
3 innodb文件系统初步入门
2 表对象缓存
1 连接层
这一篇终于到事务了,事务大家都知道ACID概念,那么mysql是如何完成事务的呢?
先来看结论——
原子性:
一次事务中的所有操作,要么全部完成要么全部不执行。这里是通过undo log来实现的。
undo log又是什么呢,可以理解为要执行的sql的反向sql,也就是回滚sql。譬如你insert了一条,undo log里就会保存一个delete xxx id = xxx。
持久性:
一旦一个事务被提交,就算服务器崩溃,仍然不能丢数据,在下次启动时需要能自动恢复。这里是通过redo log实现的。
那么如何才能持久呢,很简单,写入硬盘就行了。通过前面几篇的学习,我们知道mysql大部分时间是在Innodb_buffer_pool里做内存读写的,特定情况下才会落盘。这样如果突然服务器崩溃,没来得及落盘的数据就会丢失。所以有了redo log顺序写磁盘(顺序写速度极快,后续的落盘是随机写,速度慢),在事务提交后,事务日志会顺序写入磁盘,然后写入pool内存里。然后才是后续的那些按规则将索引数据落盘。
隔离性:
事务的隔离性是通过读写锁+MVCC来实现的。mysql在为了并发量和数据隔离方面做了很多的尝试,其中MVCC就是比较好的解决方案。
也就是面试最常见的4大隔离级别。
1.读未提交 其它事务未提交就可以读
2.读已提交 其它事务只有提交了才能读
3.可重复读 只管自己启动事务时候的状态,不受其它事务的影响(mysql默认)
4.事务串行 按照顺序提交事务保证了数据的安全性,但无法实现并发
一致性:
即数据一致性,是通过上面的三种加起来联合实现的。
ACID只是个概念,最终目的就是保证数据的一致性和可靠不丢。
Undo Log
所谓的undo log就是回滚日志,当进行插入、删除、修改操作时,一定会生成undo log,并且一定优先于修改后的数据落盘。
我直接借用别人的图了,zhangsan的银行账户有1000元,他要转400元到理财账户。
可以看到,每一条变更数据的操作,都伴随一条undo log的生成。undo log就是记录数据的原始状态。这一点在一些其他的分布式事务的框架里也有所使用,譬如seata就是采用自己解析sql并生成反向sql存储下来,将来抛异常时就执行回滚语句的方式来做的分布式事务,而不借助于mysql自身的undo log机制。
有了undo log,如果事务执行失败要回滚,那很简单,直接将undo log里的回滚语句执行一遍就好了。mysql就是通过这种方式完成的原子性。
Redo Log
redo log是完成数据持久性的,事务一旦提交,其所做的修改就会永久保存到数据库中,而不能丢失,即便是mysql服务器挂掉了也不能丢。
mysql数据是存储到磁盘的,但读写其实都是操作的buffer pool缓存(前面几篇讲过insert buffer)。这样就会造成写入时,如果仅仅写入到buffer pool了,还没来得及刷入数据页,那么mysql突然宕机,就会丢失数据。
此时redo log的作用就出来了,在写入buffer pool后会同时写入到redo log(顺序写磁盘)一份,redo log有固定的大小,会被重复使用。
MVCC及隔离级别
mvcc是什么
MVCC (MultiVersion Concurrency Control) 叫做多版本并发控制。理解为:事务对数据库的任何修改的提交都不会直接覆盖之前的数据,而是产生一个新的版本与老版本共存,使得读取时可以完全不加锁。
有点抽象是吗,再来详细解释一下。同一行数据会有多个版本,某事务对该数据的修改并不会直接覆盖老版本,而是产生一个新版本和老版共存。然后在该行追加两个虚拟的列,列就是进行数据操作的事务的ID(created_by_txn_id),是一个单调递增的ID;还有一个deleted_by_txn_id,将来用来做删除的。
那么在另一个事务在读取该行数据时,由具体的隔离级别来控制到底读取该行的哪个版本。同时,在读取过程中完全不加锁,除非用select * xxx for update强行加锁。
譬如read committed级别,每次读取,总是取事务ID最大的那个就好了。
对于Repeatable read,每次读取时,总是取事务ID小于等于当前事务的ID的那些数据记录。在这个范围内,如果某一数据有多个版本,则取最新的。
MVCC在mysql中的实现依赖的是undo log与read view
undo log记录某行数据的多个版本的数据;read view用来判断当前版本数据的可见性。
mysql就是用MVCC来实现读写分离不加锁的。
那么MVCC里多出来的那些版本的数据最终是要删除的,支持MVCC的数据库套路一般差不多,都会有一个后台线程来定时清理那些肯定没用的数据。只要一个数据的deleted_by_txn_id不为空,并且比当前还没结束的事务ID最小的一个还小,该数据就可以被清理掉了。在PostgreSQL中,该清理任务叫“vacuum”,在Innodb中,叫做“purge”。
隔离级别
隔离级别目的很明确,管理多个并发读写请求的访问顺序,包括串行和并行,要在并发性能和读取数据的正确性上做个权衡。
其中的两个隔离级别Serializable和 Read Uncommited几乎用不上,这里不谈。
Read Committed
能读到其他事务已提交的内容,这是Springboot默认的隔离级别。一个事务在他提交之前的所有修改,对其他事务不可见。提交后,其他事务就能读到了。在很多场景下这种逻辑是可以接受的。
在这个隔离级别下,读取数据不加锁而是使用MVCC机制,写入数据就是排他锁。该级别会产生不可重复读和幻读问题。
不可重复读就是在一个事务内多次读取的结果不一样,这个很容易理解,上面讲MVCC时也说了,该级别每次select时都会去读取最新的版本,所以同一个事务内,也就是代码前面一行select了,后面又select了,可能会select到不同的值。因为这两次select过程中,有其他事务对select的行进行了事务提交,就会被select出来最新的。
幻读,即一个事务能够读取到插入的新数据。会出现幻读也是一样的道理,第一次select时还没值,再次select时又有值了。
Repeatable Read
这个级别名字就是可重复读,这是mysql默认的隔离级别。
为什么能重复读,前面讲MVCC时也说了,这个级别下,一旦读到某个版本,后续都是这个版本了,好比是一次快照,就不关心其他事务对该行数据的提交了,它只认第一次读取时的版本号。
这个级别在一些场景下很重要,如
数据备份:
例如数据库S从数据库M中复制数据,但是M又不停的在修改数据。S需要拿到M的一个数据快照,但又不能停M。
数据合法性校验:
例如有两张表,一张记录了当时的交易总额,另一张记录了每个交易的金额。那么在读取数据时,如果没有快照的存在,交易总额就可能和当时的交易总额对不上。
该级别依然会出现幻读的问题,repeatable是可以出现幻读的,一个事务虽然不能读取其他事务对现有数据的修改,但是能够读取到插入的新数据。
即便是MVCC也解决不了幻读的问题,这里有一篇讲的原因。
写前提困境
尽管在MVCC的加持下Read Committed和Repeatable Read都可以得到很好的实现。但是对于某些业务代码来讲,在当前事务中看到/看不到其他的事务已经提交的修改的意义不是很大。这种业务代码一般是这样的:
先读取一段现有的数据
在这个数据的基础上做逻辑判断或者计算;
将计算的结果写回数据库。
这样第三步的写入就会依赖第一步的读取。但是在1和3之间,不管业务代码离得有多近,都无法避免其他事务的并发修改。换句话说,步骤1的数据正确是步骤3能够在业务上正确的前提,这样其实与MVCC都没什么关系了,因为我们想象中的要操作的数据和实际值并不一样,无论怎么步骤3的结果其实都不对了。
无论你用哪种隔离,你都无法解决第一步读取的数据和第三步操作之间,别的事务对它的修改。
解决方法:
结论
虽然上面写了很多,也很复杂,貌似不上锁怎么都难以解决写前提困境。而事实上,我们几乎不用考虑这样的场景,极少有可能说多个客户端同时操作同一条数据,又刚好碰上需要抉择read committed还是Repeatable read的困境。
结论很简单,不管他就好,你几乎没机会碰到这样的选择困境。
Android Log.v()、Log.d()、Log.i()、Log.w()、Log.e() - 什么时候使用它们?
不同的LogCat
方法是:
Log.v(); // VerboseLog.d(); // DebugLog.i(); // InfoLog.w(); // WarningLog.e(); // Error
使用每种类型的 Logging 的合适情况是什么?我知道这也许只是一点点语义,也许并不重要,但对于LogCat
在 Android Studio 和
Eclipse 中进行过滤,很高兴知道我在适当的时间使用了正确的方法。
答案1
小编典典让我们以相反的顺序进行:
Log.e :这是为了当坏事发生时。在 catch 语句中等位置使用此标记。您 知道 发生了 错误 ,因此您正在记录错误。
Log.w :当您怀疑发生了一些可疑的事情时使用它。你可能没有完全进入错误模式,但也许你从一些意想不到的行为中恢复过来。基本上,使用它来记录您不希望发生但不一定是错误的事情。有点像“嘿,这件事发生了,很 奇怪 ,我们应该调查一下。”
Log.i :使用它来将有用 的信息 发布到日志中。例如:您已成功连接到服务器。基本上用它来报告成功。
Log.d :将其用于 调试 目的。如果您想打印出一堆消息以便记录程序的确切流程,请使用它。如果要保留变量值的日志,请使用它。
Log.v :当你想对你的日志完全疯狂时使用它。如果出于某种原因您决定在应用程序的特定部分中记录每一件小事,请使用 Log.v 标记。
作为奖励…
- Log.wtf :当事情绝对,可怕,神圣的废话错误时使用它。你知道那些你在捕捉你 永远不 应该得到的错误的 catch 块......是的,如果你想记录它们,请使用 Log.wtf
Android Log.v(),Log.d(),Log.i(),Log.w(),Log.e() - 何时使用每一个?
不同的LogCat
方法是:
Log.v(); // Verbose
Log.d(); // Debug
Log.i(); // Info
Log.w(); // Warning
Log.e(); // Error
使用每种类型的日志记录的适当情况是什么? 我知道也许这只是一些语义,也许它并不重要,但对于Android Studio和Eclipse中的LogCat
过滤,我很高兴知道我在适当的时候使用了正确的方法。
#1楼
源代码提供了一些基本指导:
详细程度的顺序,从最小到最多,是ERROR,WARN,INFO,DEBUG,VERBOSE。 除了在开发期间,不应该将详细编译到应用程序中。 调试日志在运行时编译但被剥离。 始终保留错误,警告和信息日志。
更多细节,Kurtis的答案已经过去了。 我想补充一点:不要在INFO
或以上( WARN
/ ERROR
)记录任何个人身份信息或私人信息。 否则,错误报告或包含日志记录的任何其他内容可能会受到污染。
#2楼
Android Studio网站最近(我认为)提供了一些建议,从Kurtis的回答中可能有用的不同日志级别期望什么样的消息:
- 详细 - 显示所有日志消息(默认)。
- 调试 - 显示仅在开发期间有用的调试日志消息,以及此列表中较低的消息级别。
- 信息 - 显示常规使用的预期日志消息,以及此列表中较低的消息级别。
- 警告 - 显示尚未出现错误的可能问题,以及此列表中较低的消息级别。
- 错误 - 显示导致错误的问题,以及此列表中较低的消息级别。
- 断言 - 显示开发人员期望永远不会发生的问题。
#3楼
你可以使用LOG如:
Log.e(String, String) (error)
Log.w(String, String) (warning)
Log.i(String, String) (information)
Log.d(String, String) (debug)
Log.v(String, String) (verbose)
示例代码:
private static final String TAG = "MyActivity";
...
Log.i(TAG, "MyClass.getView() — get item number " + position);
#4楼
虽然这个问题已经回答了,但我觉得答案中有缺少的例子。
因此,我将把我在博客文章“Android Log Levels”中写的内容带到这里
详细
是最低级别的日志记录。 如果你想坚持记录,那么你就可以使用这个级别了。 我从来不知道何时使用Verbose以及何时使用Debug。 差别对我来说非常武断。 一旦我指出Android¹的源代码,我终于理解了“除了在开发过程中,不应该将Verbose编译成应用程序。”现在我很清楚,无论何时开发并想要添加可删除的日志来帮助你开发有用的是详细级别,这有助于您在投入生产之前删除所有这些日志。
调试
用于调试目的。 这是生产中应该达到的最低水平。 这里的信息是在开发过程中提供帮助。 大多数情况下,您将禁用此生产日志,以便发送较少的信息,并且只有在出现问题时才启用此日志。 我喜欢登录调试应用程序从服务器发送/接收的所有信息(注意不要记录密码!!!)。 这对于了解错误是在服务器还是应用程序中非常有帮助。 我还会记录进入和退出重要功能的日志。
信息
有关突出显示应用程序进度的信息性消息。 例如,当应用程序的初始化完成时。 当用户在活动和片段之间移动时添加信息。 记录每个API调用,但只记录URL,状态和响应时间等信息。
警告
当存在潜在的有害情况时。
这个日志在我的经历中是一个棘手的水平。 你什么时候有潜在的有害情况? 一般情况下或它是好的或它是一个错误。 我个人不太喜欢这个级别。 我使用它的例子通常是多次发生的事情。 例如,用户的密码错误超过3次。 这可能是因为他错误地输入了3次密码,也可能是因为我们的系统中没有接受某个字符存在问题。 网络连接问题也是如此。
错误
错误事件。 错误后应用程序仍可继续运行。 这可能是例如当我得到一个空指针,我不应该得到一个。 解析服务器的响应时出错。 从服务器收到错误。
WTF(多么可怕的失败)
致命是导致应用程序退出的严重错误事件。 在Android中,致命的是实际上的错误级别,不同之处在于它还添加了fullstack。
#5楼
我们按相反顺序进行:
Log.e :这是为了发生坏事。 在catch语句中使用此标记。 您知道发生了错误 ,因此您正在记录错误。
Log.w :当你怀疑阴影正在发生时使用它。 您可能无法在错误模式下完全完整,但也许您从某些意外行为中恢复过来。 基本上,使用它来记录您不希望发生的事情,但不一定是错误。 有点像“嘿,这发生了,而且很奇怪 ,我们应该调查它。”
Log.i :使用此命令将有用信息发布到日志中。 例如:您已成功连接到服务器。 基本上用它来报告成功。
Log.d :用于调试目的。 如果要打印出大量消息,以便记录程序的确切流程,请使用此方法。 如果要保留变量值的日志,请使用此选项。
Log.v :当您想要完全记录日志时使用此选项。 如果由于某种原因您决定在应用程序的特定部分记录每个小东西,请使用Log.v标记。
作为奖励......
- Log.wtf :当东西绝对可怕时,使用这个,可怕的,神圣的错误。 你知道那些捕获块,你捕获的错误,你永远不会得到...是的,如果你想记录它们使用Log.wtf
关于如何在 swift-log 消息中自动包含源?和swift 自定义cell的介绍现已完结,谢谢您的耐心阅读,如果想了解更多关于3000 帧动画图解 MySQL 为什么需要 binlog、redo log 和 undo log、7 mysql事务(包括redo log,undo log,MVCC)及事务实现原理、Android Log.v()、Log.d()、Log.i()、Log.w()、Log.e() - 什么时候使用它们?、Android Log.v(),Log.d(),Log.i(),Log.w(),Log.e() - 何时使用每一个?的相关知识,请在本站寻找。
本文标签: