隐式链接隐式链接

I assume every Android developer knows and uses the logging facilities provided by the Android SDK. For example, when you need to log something for debugging purposes, you’d end up writing something like that:

我假设每个Android开发人员都知道并使用Android SDK提供的日志记录功能。 例如,当您需要记录某些东西以进行调试时,最终会写出这样的东西:

Log.d("MainActivity", "Here comes the story of a sleepless night which was spent trying to nail that nasty issue...");

The first argument is the tag:

第一个参数是标记:

* @param tag Used to identify the source of a log message.  It usually identifies the class or activity where the log call occurs.

Sooner or later you may find out that you need more flexibility with your logs — let’s say that you want to send all crash reports into the Firebase Crashlytics service (but only if they are from release builds, since on debug builds you want them to end up in logcat only), you want your debug logs to be sent to the special SQLite table, etc., etc. This is where some developers end up using the library called Timber. The thing that you notice immediately is that you don’t need to specify the tag:

或早或晚,您可能会发现日志需要更大的灵活性-假设您要将所有崩溃报告发送到Firebase Crashlytics服务中(但仅当它们来自发行版本时,因为在调试版本中,您希望它们结束(仅在logcat中),您希望将调试日志发送到特殊SQLite表等。在这里,某些开发人员最终使用了名为Timber的库。 您立即注意到的是,您无需指定标签:

Timber.d("Another sleepless night, same issue, but at least we don't need tags...");

And yet when you look at the logcat, the tag is here:

但是,当您查看logcat时,标记在这里:

05-01 21:39:10.763 9350-9350/com.application D/MainActivity: Another sleepless night, same issue, but at least we don't need tags...

I admit, when I started using Timber, I didn’t stop to think how exactly does it work. It’s time to fill that knowledge gap.

我承认,当我开始使用Timber时,我没有停止思考它到底是如何工作的。 现在是时候填补这一知识空白。

一切都以logcat结尾... (It all ends with the logcat…)

…so this is where we’re going to start looking. I was using the Java version of Timber, so here’s the link if you want to take a look for yourself.

…所以这就是我们要开始寻找的地方。 我使用的是Java版本的Timber,因此如果您想自己看看,这里是链接 。

My initial idea was that if the logged lines end up in the logcat, we need to search for some standard log invocations (e.g. Log.d ), and we’ll see how the tags are created. The search raises nothing of the sort, but there is something else (lines 425–428):

我最初的想法是,如果记录的行最终出现在logcat中,我们需要搜索一些标准的日志调用(例如Log.d ),然后我们将了解如何创建标签。 搜索不会产生任何东西,但是还有其他东西(第425-428行):

If you scroll further, you’ll see more and more invocations of prepareLog . Ok, that’s something, let’s see what’s going on in this method (lines 530–555):

如果进一步滚动,将看到越来越多的prepareLog调用。 好的,就是这样,让我们​​看看这种方法的作用(第530-555行):

Does it look like the tag is created in getTag (lines 401–408)?

看起来标签是在getTag创建的(第401-408行)吗?

No, apparently not.

不,显然不是。

显式标签? 我以为我们在这里谈论隐式的! (Explicit tags? I thought we’re talking about implicit ones here!)

All getTag does is it gets the tag from the explicitTag field (which has the type of ThreadLocal ; I’m not going to discuss it in detail here, except for saying that this class provides thread-local variables — each thread that accesses ThreadLocal variable gets its own copy of it, which is inaccessible to other threads). But if it gets the tag from the ThreadLocal container, then it means that someone puts it in here, right? Let’s search for explicitTag.set (we have a single result, lines 135–144):

getTag所做的只是从“ explicitTag字段(其类型为ThreadLocal ;从这里获取标记)中获取标签,除了说该类提供线程局部变量(每个访问ThreadLocal变量的线程)外,这里不再详细讨论。获取它自己的副本,其他线程无法访问该副本)。 但是,如果它从ThreadLocal容器中获取标签,则意味着有人将其放在这里,对吗? 让我们搜索explicitTag.set (我们有一个结果,第135–144行):

Ok, I feel like we’re getting to the end of the journey. How does the actual call of the tag method look like?

好的,我觉得我们已经结束了旅程。 tag方法的实际调用是什么样的?

Well, there’re no invocations of that method in Timber , so I assume that’s a dead end. Let’s return to the previous step and look at getTag again. This method is defined in the abstract class called Tree , and it is overridden in the class called DebugTree , so let’s take a look at how the overridden version looks like (lines 615–629):

好吧,在Timber没有该方法的调用,所以我认为那是一个死胡同。 让我们返回上一步,再次查看getTag 。 该方法在名为Tree的抽象类中定义,并且在名为DebugTree的类中被DebugTree ,因此让我们看一下被覆盖的版本的样子(第615–629行):

Wait, what? Do we create an instance of Throwable only to get a tag from its stack trace?

等一下 我们是否仅创建Throwable实例以从其堆栈跟踪中获取标签?

We do (lines 600–613):

我们这样做(第600–613行):

StackTraceElement#getClassName does the following:

StackTraceElement#getClassName执行以下操作 :

Returns the fully qualified name of the class containing the execution point represented by this stack trace element.

返回包含此堆栈跟踪元素表示的执行点的类的完全限定名称。

The mystery is solved. What I thought was achieved through the dark reflection witchery ended up being nothing more than a smart usage* of a Throwable instance.

谜团解决了。 我认为通过黑暗反射巫术实现的最终结果无非是Throwable实例的明智用法。

还有一件事 (One more thing)

By the way, if we take a look at the comment accompanying the createStackTraceElement , we’ll notice the following comment:

顺便说一下,如果我们看一下createStackTraceElement附带的注释,我们会注意到以下注释:

Note: This will not be called if a {@linkplain #tag(String) manual tag} was specified.

Ok, now I get why do we need the tag method that we’ve encountered before and why we didn’t see it being invoked in the Timber source code. This method is meant to be used in cases where we want to override the tag extracted from the stack trace with our own tag for the next logging call. And the most likely reason for storing it in the ThreadLocal container is that we don’t want to end up having a race condition.

好的,现在我明白了为什么我们需要之前遇到的tag方法以及为什么我们没有在Timber源代码中看到它被调用。 此方法适用于以下情况:我们要使用下一个日志记录调用的标记覆盖从堆栈跟踪中提取的标记。 将其存储在ThreadLocal容器中的最可能的原因是我们不想最终遇到竞争状况。

For example, Thread A sets an explicit tag to be used for the next logging call, but Thread B gets its chance to access the explicit tag first, effectively using the tag for its intents and purposes (while it shouldn’t). After that, it might get a chance to clean up the explicit tag before Thread A accesses it (which is wrong, because Thread A needs it) or it will not manage to clean it up soon enough (which is also illegal, since Thread A will use the explicit tag and we’ll end up having two log lines with an explicit tag which was meant to be used once). ThreadLocal container solves this issue nicely by making sure each thread has its own copy of an explicit tag, and no other thread can access it.

例如,线程A设置了一个显式标签以用于下一次日志记录调用,而线程B则有机会首先访问该显式标签,并有效地利用该标签的意图和目的(但不应这样做)。 之后,它可能有机会在线程A访问它之前清除显式标记(这是错误的,因为线程A需要它),否则它将无法尽快清除它(这也是非法的,因为线程A)将使用显式标签,我们最终将获得两个带有显式标签的日志行,该显式标签本应使用一次)。 ThreadLocal容器通过确保每个线程都有自己的显式标记副本,并且没有其他线程可以访问它,很好地解决了此问题。

Ok, this definitely was an exciting journey, and I hope you’ve learned a trick or two here. Stay tuned for the next articles!

好的,这绝对是一个令人兴奋的旅程,希望您在这里学到了一两个技巧。 请继续关注下一篇文章!

Notes

笔记

* Another clever (or should I say non-ordinary instead?) usage of exceptions was in some Python project I’ve heard about a couple of years ago. Unfortunately, I don’t remember the project’s name, but I still remember that the exceptions were being used here to pass the information and control between various parts of a program, so the result looked much more like an event bus, than the mechanism to handle the exceptional situations.

*另一个聪明的(或者我应该说非常规的)异常用法是在几年前我听说的一些Python项目中。 不幸的是,我不记得项目的名称,但是我仍然记得这里使用了异常在程序的各个部分之间传递信息和控制,因此结果看起来更像是事件总线,而不是机制。处理特殊情况。

翻译自: https://medium.com/swlh/on-timbers-implicit-tags-selection-19687117dbc7

隐式链接隐式链接


http://www.taodudu.cc/news/show-5334395.html

相关文章:

  • 163个人邮箱忘记密码找回有几种方法
  • 自定义百度地图样式
  • 百度地图的开发者模式
  • 短视频部门工作流程SOP计划表方案
  • ❤️手把手教你做一个爱情保温软件❤️——python封装.exe文件+爬虫(每日情话系列)
  • 23个完整应用下载
  • iphone最受欢迎幼教软件:宝贝全计划
  • 你过来,我给你看个宝贝
  • 我去!CSDN还有这宝贝——CSDN浏览器插件深度评测
  • 后台推广数据下载处理导入数据库
  • 成龙《宝贝计划》精彩场景小结
  • 宝贝云计划IOS端项目小结
  • 【壁纸宝贝】开源计划
  • 第三次人机界面
  • redisson 主从模式Unsupported protocol version 50_《DNF》希洛克挑战模式专属智慧产物有哪些 产物汇总一览...
  • redisson 主从模式Unsupported protocol version 50_洛克王国轻风山怎么进入|DNF希洛克挑战模式专属智慧产物是什么-DNF希洛克挑战模式专属智慧产物介绍...
  • 关于最近DNF刷图频繁出现验证码的解决方案
  • Partial Differential Equation Toolbox
  • Differential flatness
  • Programming Differential Privacy第五章
  • Local Differential Privacy for Deep Learning
  • Differential privacy——差分隐私
  • Self-adaptive Differential Evolution Algorithm for Numerical Optimization
  • JADE: Adaptive Differential Evolution withOptional External Archive
  • Self-adaptive Differential Evolution with Neighborhood Search
  • Functional Mechanism: Regression Analysis under Differential Privacy
  • Programming Differential Privacy第七章
  • Making a Difference to Differential Evolution
  • Partial differential equation
  • Different and differential(不同和差异的区别)

隐式链接隐式链接_在木材上隐式标签选择相关推荐

  1. 热式气体质量流量计检定规程_最佳实践:热式质量流量计实际标定的安全性和准确性...

    流量计实际标定的重要性 所有流量计都不能想当然的进行标定.流量计可以配置最具有工业可靠性的传感器技术,生产为最高安全等级.性能最优.功能丰富的设备.但是如果流量计标定不准确,或者是因为等效标定.模拟标 ...

  2. 过去式加ed的发音_小学英语动词过去式归类总结

    小学英语动词过去式归类总结   一.动词过去式的规则变化 1. 一般情况下,动词词尾加-ed 如:work ---worked, play---played, want----wanted, act- ...

  3. sql隐式连接和显示链接_SQL Server中的嵌套循环联接–批处理排序和隐式排序

    sql隐式连接和显示链接 In SQL Server, it`s not always required to fully understand the internal structure, esp ...

  4. 《数据结构课程实践》_02_隐式图的搜索问题_准备工作

    02_隐式图的搜索问题_准备工作 一.实验题目与要求 二.编程语言以及开发环境 三.实验思路 A*算法 四.预习小结 一.实验题目与要求 实验要求: 对九宫重排问题,建立图的启发式搜索求解方法: 用A ...

  5. 《数据结构课程实践》_02_隐式图的搜索问题_实现

    02_隐式图的搜索问题_实现 一.实验题目 二.编程语言以及开发环境 三.源代码 1.main类 2.节点类 3.算法类 四.运行结果 五.实验小结 一.实验题目 实验要求: 对九宫重排问题,建立图的 ...

  6. 计算机图形学九:几何1—隐式曲面(代数形式,CSG, 距离函数,分型几何)与显式曲面

    隐式曲面与显式曲面 1 隐式曲面(Implicit Surface)与显示曲面(Explicit Surface)的特点 1.1 隐式曲面的特点 1.2 显式曲面的特点 2 具体的几种隐式曲面 2.1 ...

  7. 编程三角形面积公式_三角形面积公式110式(英文版)

    点击上面蓝色文字关注杨志明数学角精华博览8年新课标I.5年新课标II.4年新课标III高考数学真题详细解析16年新课标I.9年新课标II.4年新课标III高考数学真题分类详解2020年高考数学重要专题 ...

  8. python 隐马尔科夫_机器学习算法之——隐马尔可夫(Hidden Markov ModelsHMM)原理及Python实现...

    前言 上星期写了Kaggle竞赛的详细介绍及入门指导,但对于真正想要玩这个竞赛的伙伴,机器学习中的相关算法是必不可少的,即使是你不想获得名次和奖牌.那么,从本周开始,我将介绍在Kaggle比赛中的最基 ...

  9. 响应式多级菜单 侧边菜单栏_大菜单,小屏幕:响应式,多级导航

    响应式多级菜单 侧边菜单栏 如果您曾经在响应式网站上工作,那么毫无疑问,您必须解决这个新兴领域中最棘手的问题之一:导航. 对于简单的导航,解决方案可以很简单. 但是,如果您要处理的事情比较复杂,可能有 ...

最新文章

  1. Anchor Boxes示例实战
  2. Makefile 中:= ?= += =的区别
  3. docker新建Linux虚拟机,RHEL/CentOS 7下创建你的第一个Docker容器
  4. ROS安装:Ubuntu18.04安装配置ROS-melodic
  5. 冒泡排序html代码,冒泡排序.html
  6. 为operamasks增加HTML扩展方式的组件调用
  7. 江苏师范大学科文学院计算机科学与技术,2019江苏师范大学科文学院专业排名...
  8. azure不支持哪些语句 sql_新同事不讲武德,这SQL语句写得忒野了
  9. SpringBoot+Vue项目上手
  10. Java并发(基础知识)—— 创建、运行以及停止一个线程
  11. cookie实现上次访问时间
  12. 苹果账号续费以及过期更新问题
  13. pycharm中python的默认安装路径_PyCharm下载和安装详细步骤
  14. opencv保存视频编码方式
  15. Unity的ScrollRect如何裁切粒子特效,以及如何使粒子特效显示在UI上
  16. PySide2学习总结(十二)打开文件对话框--FileDialog
  17. 第三十届香港金像奖(转)
  18. art-pi lvgl添加触摸事件部分代码
  19. 杭电计算机考研复试经验帖
  20. html蒙尘效果,vr看车.html

热门文章

  1. 微信小程序门诊医院体检挂号缴费药品信息管理系统+后台管理系统SSM-JAVA【数据库设计、论文、源码、开题报告】
  2. 聊城计算机教师资格证面试,2017年下半年教师资格证面试通过率有多少?
  3. 误删Android手机通讯录,安卓手机联系人数据误删了怎么找回
  4. 分布式事务——Saga实现思路
  5. Epox 主板故障代码:FF
  6. 阿里免费服务器测试题及答案
  7. LILO-Linux引导程序
  8. JESD204接口调试总结——一次建链不稳定问题的解决
  9. 同花顺python api_量化交易。最新版通用版同花顺客户端的Python3 API
  10. 请重视学习习惯和学习方法的培养