Logging 日志记录最佳实践-在目标方法开始时记录方法调用或日志?
我们什么时候登录?在函数调用之前(示例A)还是在目标方法的开头(示例B) 注意,这个问题是关于确切的记录器函数调用位置,而不是一般的最佳日志记录实践 解决方案A:在函数调用时记录:Logging 日志记录最佳实践-在目标方法开始时记录方法调用或日志?,logging,language-agnostic,coding-style,Logging,Language Agnostic,Coding Style,我们什么时候登录?在函数调用之前(示例A)还是在目标方法的开头(示例B) 注意,这个问题是关于确切的记录器函数调用位置,而不是一般的最佳日志记录实践 解决方案A:在函数调用时记录: function someProcess() { log.info("Reading data"); readDataFromIO(); log.info("Outputing data"); outputDataToScreen(); } // ... other module:
function someProcess() {
log.info("Reading data");
readDataFromIO();
log.info("Outputing data");
outputDataToScreen();
}
// ... other module:
function readDataFromIO() {
...
}
function outputDataToScreen() {
...
}
function someProcess() {
readDataFromIO();
outputDataToScreen();
}
// ... other module:
function readDataFromIO() {
log.info("Reading data");
...
}
function outputDataToScreen() {
log.info("Outputing data");
...
}
解决方案B:在方法开始时记录:
function someProcess() {
log.info("Reading data");
readDataFromIO();
log.info("Outputing data");
outputDataToScreen();
}
// ... other module:
function readDataFromIO() {
...
}
function outputDataToScreen() {
...
}
function someProcess() {
readDataFromIO();
outputDataToScreen();
}
// ... other module:
function readDataFromIO() {
log.info("Reading data");
...
}
function outputDataToScreen() {
log.info("Outputing data");
...
}
在解决方案A中,当效率问题出现时,您可以自定义消息或放弃日志记录,但如果日志消息看起来相同,您可能会忘记记录,并且会有大量重复的代码。在解决方案B中,不存在忘记日志记录和代码复制的风险,但您不能100%关闭日志记录逻辑,如果方法调用中出现错误(如空指针异常),您就会遇到麻烦哪种是最佳做法?最佳做法:
- 使用某种记录器类/模块(取决于语言),允许您在不同级别(调试、信息等)进行日志记录
- 日志级别调试中非常基本的函数
- 在日志级别信息中记录更复杂的函数(例如,调用其他基本函数的函数)
- 使用日志级别警告记录潜在问题
- 日志错误和带有日志级别错误的异常
这一过程在很大程度上取决于您使用的语言(当然),但我认为这种“log4j”方法是一种非常好的方法。以下是我根据自己的经验可以给您的提示(因为您已将此主题标记为不可知语言,我将保持通用性):
- 使用委托函数(或使用日志函数创建中心日志类)记录消息。参数应包含日志消息、日志严重性和日志级别。 此委托函数(或日志类中的函数)应在需要记录日志的任何地方调用。 它允许您轻松替换日志机制,例如从基于文件的日志更改为Windows事件日志。 在此功能中,您还可以处理日志级别,即使其可配置为抑制警告等
- 在
中添加一个try-catch以允许捕获运行时错误someProcess()
- 当你开始某件事,当你结束某件事时都要记录,并且总是记录可能发生的错误。这些日志调用可以在函数内部本地进行,如示例B所示
- 如果您使用的语言支持这一点,那么编写一个记录异常的函数/方法:例如,在C#中,您可以为异常编写一个
,然后允许您在每个catch块中简单地调用它,比如:公共静态无效日志(此异常示例){/..logging code…}
try{…}catch(Exception ex){ex.Log();}
它还可用于向其添加可选参数,如
,因此您可以向其传递其他信息,如public static void Log(此Exception ex,string message=“”){…logging code…}
ex.Log(“readDataFromIO()-发生读取错误”)代码>
如果可能的话,看看你正在使用的框架或语言是否已经有这样一个类(通常是这样),并使用它或开发你自己的框架(即你自己的集中式日志类),而不是完全重新发明轮子。除了前面提到的,我使用的是某种广义的日志概念。它帮助我发现某些情况确实比预期的更频繁或更少出现的情况 我正在使用一个类
LogEvent
(代码是Java
,但idea可以移植到大多数语言):
如何引发事件并收集事件发生情况?
LogEvents
可以使用LogEventCollection
进行“注册”:
import java.util.Map;
import java.util.TreeMap;
public class LogEventCollection {
private Map<String, LogEvent> events;
public EventCollection() {
events = new TreeMap<String, Event>();
}
public void register(String name) {
LogEvent ev;
if (events.containsKey(name)) {
ev = events.get(name);
ev.inc();
}
else {
ev = new LogEvent(name);
events.put(name, ev);
}
}
public void report(String title, int minCount) {
Util.info("");
if (!title.isEmpty()) {
Util.info(title);
}
for (LogEvent ev : events.values()) {
if ((minCount < 0) || (ev.count() >= minCount)) {
ev.report();
}
}
Util.info("");
}
}
import java.util.Map;
导入java.util.TreeMap;
公共类LogEventCollection{
私人地图活动;
公共事件集合(){
events=newtreemap();
}
公共无效寄存器(字符串名称){
LogEvent ev;
if(events.containsKey(name)){
ev=events.get(名称);
ev.inc();
}
否则{
ev=新日志事件(名称);
事件。put(名称,ev);
}
}
公共作废报告(字符串标题,int minCount){
Util.info(“”);
如果(!title.isEmpty()){
实用信息(标题);
}
对于(LogEvent ev:events.values()){
如果((minCount<0)| |(ev.count()>=minCount)){
ev.报告();
}
}
Util.info(“”);
}
}
为了获得程序内部事件的概览,方法LogEventCollection
给出了所有LogEvents
的列表,以及它们各自的计数。此列表可以按名称或事件频率排序
多线程应用程序需要额外的锁定代码或线程安全集合,以防止并发访问LogEventCollection期间发生冲突
显然,这种方法可以通过添加条件事件来扩展(=调用
register()
受到某些条件的保护)。或者,可以在生产运行期间禁用事件日志记录 当然,最好的做法是将日志记录放在需要的地方。:-)但在你的例子中,最好的做法是