使用注释进行跟踪日志记录

发布于 2024-10-31 11:25:21 字数 1247 浏览 1 评论 0原文

我一直在与一家公司的代码库合作,该公司的政策是编写大量跟踪日志记录。因此,几乎每个方法都有一段这样开始的代码:

String LOG_METHOD = "nameOfMethod(String,List<Long>):void";
if(logger.isTraceEnabled()) { 
    Object[] params = new Object[] { string, list };
    logger.trace(CompanyMessages.newMethodInstanceMessage(this, LOG_METHOD, params)); 
}

和这样结束(在 finally 子句中或在方法的末尾:

if(logger.isTraceEnabled()) { 
    logger.trace(CompanyMessages.leaveMethodInstanceMessage(this, LOG_METHOD)); 
}

实际上还有更多代码,但这是基本思想。 这使得代码变得混乱,并且其他编码人员不断地用他们自己的解释来搞乱它,这些解释不使用特定的CompanyMessages类,该类需要格式化监视工具读取的消息。因此,我正在寻找一种方法来摆脱上面的所有代码,只提供所有需要使用注释进行跟踪记录的方法,例如:@LogBefore('logLevel') & ; @LogAfter('logLevel')

我选择这个解决方案的原因是为了让其他开发人员不必学习任何新东西,只需使用注释而不是代码。我在一个服务器环境中工作,我们在其中部署了数百个 Web 应用程序和数十名开发人员。因此,我一直在寻找一种在 Web 应用程序中实现此功能的方法,而无需大量额外的编码或额外的大型库。这意味着我正在寻找一个小型、稳定的 AOP 实现,使用类似于我建议的注释,易于在每个 Web 应用程序中配置。性能也很重要。使用 AOP 实现这个的最简单的例子是什么?

编辑:我确实发现非常相似的东西我正在寻找什么,但这有几个问题。必须配置所有需要日志记录的类,这比仅使用注释需要更多的资源。 spring 配置 可以解决这个问题吗?

I've been working with a codebase of a company that has a policy of writing lots of trace logging. So pretty much every method has a piece of code that starts like this:

String LOG_METHOD = "nameOfMethod(String,List<Long>):void";
if(logger.isTraceEnabled()) { 
    Object[] params = new Object[] { string, list };
    logger.trace(CompanyMessages.newMethodInstanceMessage(this, LOG_METHOD, params)); 
}

and end like this (either in a finally-clause or just at the end of the method:

if(logger.isTraceEnabled()) { 
    logger.trace(CompanyMessages.leaveMethodInstanceMessage(this, LOG_METHOD)); 
}

There is actually more code to it, but this is the basic idea.
This is cluttering the code and other coders are constantly messing it up with their own interpretations which don't use the specific CompanyMessages-class which is needed to format the messages to be read by the monitoring tools. So I am looking for a way to get rid of all code above and just provide all methods which need trace-logging with annotations like: @LogBefore('logLevel') & @LogAfter('logLevel').

The reason I choose this solution is to make it so other developers don't have to learn anything new but to use annotations instead of code. I'm working in a server environment in which we deploy hundreds of web applications and dozens of developers. So I have been looking for a way to implement this in a web application without a lot of extra coding or additional large libraries. This means I'm looking for a small, stable AOP implementation using annotations similar to those I proposed, easy to configure in each web application. Performance is also important. What is the simplest example to implement this with AOP?

Edit: I did find something very similar to what I'm looking for, but this has a couple of problems. All classes that need logging must be configured, which would be more resource intensive than just using annotations. Would the spring configuration <aop:aspectj-autoproxy/> fix that?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

淑女气质 2024-11-07 11:25:21

看起来面向方面编程(AOP)确实可以帮助你解决这个问题。它非常适合解决这些横切问题,例如日志记录和跟踪,并且它支持您需要的注释。

查看 AspectJ 或 Spring AOP。

它将涉及一些 AOP 原则和您选择的 API 的学习,但这绝对值得付出努力。特别是日志记录和跟踪是您将遇到的第一个 AOP 教程,而且无需深入了解即可轻松完成。

Looks like Aspect Oriented Programming (AOP) could really help you with this. It's great at solving these cross-cutting concerns like logging and tracing and it supports annotations like those you need.

Have a look at AspectJ or Spring AOP.

It will involve some learning of the AOP principles and the API you choose but it's definitely worth the effort. Especially logging and tracing are among the first AOP tutorials you will encounter and it's pretty easy to do without having to go deeper.

没︽人懂的悲伤 2024-11-07 11:25:21

注解和AOP点都是有效的。使用注释向 AOP 框架发出有关日志记录的警报。

我要做的另一件事是修复你的记录器。

你可以:

String LOG_METHOD = "nameOfMethod(String,List<Long>):void"
if(logger.isTraceEnabled()) { 
    Object[] params = new Object[] { string, list };
    logger.trace(CompanyMessages.newMethodInstanceMessage(this, LOG_METHOD, params) ); 
}

相反,考虑这样的事情:

logger.trace(this, LOG_METHOD, string, list);

你可以像这样实现它:

public void trace(Object obj, Object args...) {
    if (parentLogger.isTraceEnabled()) {
        logger.trace(CompanyMessages.newMethodInstanceMessage(obj, LOG_METHOD, args);
    }
}

大多数日志记录实用程序都是在 Java 中使用可变参数之前编写的,所以我们仍然会看到像你所写的那样的东西。

我们还仍然希望保护措施能够防止在未启用日志时调用日志,但这样做的主要动机是因为过去大多数人都会做您所做的事情,或者更糟糕的是:

logger.trace("My message: " + string + " with list " + list);

无论启用跟踪还是启用跟踪,它都有一个昂贵的表达式不是。

但通过利用可变参数,您可以同时获得两者。只需使用诸如 MessageFormat 之类的东西(您可能已经在这样做了),您就可以轻松地得到:

logger.trace("My message: {0} with list {1}", string, list);

禁用跟踪后,这是一个传递 3 个指针的廉价方法调用。因此,保护​​它并使代码变得混乱的动机要少得多。

大多数现代记录器都不能很好地重写,因此您通常必须封装它而不是简单地扩展它。

它不会直接解决您的问题,而是动态生成跟踪信息。但这是一个简单的中间立场,可以轻松地、逐步地​​清理现有的代码库。

此外,还有其他 2 个选项。

一是使用后处理器运行您的代码并将登录添加到尚不存在的位置。这减轻了您全部手动输入的负担,但它确实使代码变得混乱(因为它仍然存在于任何地方)。

二是在编译时使用注释处理器。这是更复杂的。但它的作用是在编译期间,它会在编译时运行并使用信息来增强您的类。好处是您的代码很干净(也许除了注释),而且所有工作都是在编译时完成的。没有运行时影响,也没有对象工厂的精美类加载器。一旦构建完成,您就可以扔掉处理器,在运行时根本不需要它。

有一个项目利用了这一点,但我忘记了它的名字。它会在编译时自动将 setter/getter 添加到代码中。我听说过一些关于它的好消息。

AOP 框架很可能在编译时为您完成此操作,我对它们还不够熟悉,但无论如何,该技术都值得探索。

不过,至少要包装好您的记录器。它是增量的、安全的,并且会逐渐清理您的代码并帮助您记录注释通常不适合您的情况。

The annotations and AOP points are both valid. Use annotations to alert the AOP framework about the logging.

Another thing I would do is fix your logger.

You have:

String LOG_METHOD = "nameOfMethod(String,List<Long>):void"
if(logger.isTraceEnabled()) { 
    Object[] params = new Object[] { string, list };
    logger.trace(CompanyMessages.newMethodInstanceMessage(this, LOG_METHOD, params) ); 
}

Instead, consider something like this:

logger.trace(this, LOG_METHOD, string, list);

and you can implement it like this:

public void trace(Object obj, Object args...) {
    if (parentLogger.isTraceEnabled()) {
        logger.trace(CompanyMessages.newMethodInstanceMessage(obj, LOG_METHOD, args);
    }
}

Most of the logging utilities were written before we had varargs in Java, so we still see things like what you've written.

We also still want the guarding to prevent calling log when it's not enabled, but the primary motivation for that is because most folks in the past would do what you did, or, even worse:

logger.trace("My message: " + string + " with list " + list);

Which has has an expensive expression whether trace is enabled or not.

But by leveraging varargs, you can get both. Simply use something like MessageFormat (which you are probably doing already), you can easily get:

logger.trace("My message: {0} with list {1}", string, list);

With trace disabled, this is a cheap method call passing 3 pointers. So there is far less motivation to guard it and clutter your code.

Most of the modern loggers don't override nicely, so you typically have to encapsulate it rather than simply extend it.

It doesn't directly solve your issue, dynamically generating trace information. But it's a simple middle ground that readily, and incrementally, clean up your existing code base.

Also, there's 2 other options.

One, is to use a post processor that runs through your code and adds the logging in to places where it doesn't already exists. This saves you the burden of typing is all by hand, but it does clutter the code (since it still exists EVERYWHERE).

Two, is to use an annotation processor at compile time. This is more sophisticated. But what it does is during compilation, it runs through and augments your classes at compile time with the information. The nice thing is that your code is clean (save perhaps for the annotaion), but also all of the work is does at compile. There's not runtime impact not fancy classloaders of Object factories. Once it is built, you can toss your processor away, it's not needed at runtime at all.

There's a project, who's name escapes me, that leverages this. It automatically adds setters/getter to your code at compile. I've heard good things about it.

The AOP frameworks may well do this for you at compile, I'm not familiar enough with them to say, but either way, the technique is worth exploring.

At a minimum, though, wrap your logger. It's incremental, safe, and will gradually clean your code and aid your logging where the annotations may not work for you in general.

爱已欠费 2024-11-07 11:25:21

我不认为注释是解决方案。注释类或实例意味着在运行时为类提供附加信息,其本身不执行任何操作。您需要一些代码来处理带有注释的类,并在运行时根据这些注释在每个方法之前和之后添加代码。

因此,没有办法添加注释并准备好,您的类开始记录它们的方法。

解决方案应该是 AOP——这正是 AOP 最初被发明的问题。在每个方法上定义类/方法/操作,问题就解决了。

好吧,也许你可以让它在运行时使用注释和修改类,但你最终会得到自制的 AOP :-)

I don't think annotations were the solution. To annotate a class or instance means giving classes additional information at runtime, per se it does not do anything. You would need some code that processes classes with annotations and adds code before and after each method based on those annotations during runtime.

So there is no way on adding annotations and ready to go, you classes start log their methods.

The solution should be AOP - this exact the problem AOP has been invented in the first place. Define classes/methods/actions on each method and you have you problem solved.

Well, probably you can make it work with annotations and modifying classes during runtime but you end up with self made AOP :-)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文