Bug 559532 - [releng] Use SLF4J rather than LOG4J
Summary: [releng] Use SLF4J rather than LOG4J
Status: NEW
Alias: None
Product: OCL
Classification: Modeling
Component: Core (show other bugs)
Version: unspecified   Edit
Hardware: PC Windows 10
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: OCL Inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords: helpwanted
Depends on: 578403
Blocks:
  Show dependency tree
 
Reported: 2020-01-25 03:20 EST by Ed Willink CLA
Modified: 2022-02-08 09:58 EST (History)
4 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Ed Willink CLA 2020-01-25 03:20:59 EST
cross-project-devreports that log4j is dead and recommends the slf4j facade that can still be log4j if that's waht an overall applicaation wants.

Change log4j to slf4j.
Comment 1 Ed Willink CLA 2020-01-25 05:42:50 EST
Ouch! This is a major RSI-inducing exercise ...

The Impact Analyzer currently uses java.util.logging which is an alternative SLF4J delegate. Sinbce the code is 90% deprecated why bother to disrupt it with a new dependency. But usrs with no disuption requirements shuld be on old code anyway. Change it. No. The API is not identical. Leave Impact Analyzer unchanged.

Tess play games with the log4j ConsoleAppender etc. No ploint chnaging, since the test code is the final application. It is only non-test plugins that need yo migrate to slf4j.

The ExtensibleQuickfixProvider uses Xtext's StopWatch that uses the log4j logger. Clone a local copy for slf4j.

Which just leaves org.eclipse.ocl.examples.debug.evaluator.OCLAbstractTracingEvaluationVisitor whose constructor directly uses logger.getAppender() to fork a file copy of the log. The code seems unchnaged since first written (cloned from QVTo). Not sure that it is every useful. Deleting OCLAbstractTracingEvaluationVisitor and its OCLTracingEvaluationVisitor derivation demonstrates that tracing functionality took a different direction.

Three calls to logger.info/error needed toString() to convert the old Object argument to the new String.

Five ProjectMap tests fail that use a TestCaseLogger to explicitly check log messages.
Comment 2 Ed Willink CLA 2020-01-25 11:24:02 EST
Tests fail since no LOG4J deleegate installed.

On no account install "LOG4J implemented over SLF4J" org.slf4j.apis.log4j; it doesn't have a full API; e.g. ThrowableInformation, so you get stuck with a bad fragment fightong org.apache.log4j. org.slf4j.log4j seems really bad too.

org.slf4j.impl.log4j12_1.7.2.v20131105-2200.jar seems to have the required StaticLoggerBinder. But org.slf4j.impl.log4j12 is not importable; MANIFEST refuses to see it even though Installed Software plaugins liust it.

org.slf4j.impl.log4j12.source is importable just to demonstrate the confusion/lack of typo.

org.slf4j.impl.log4j12 is a fragment of org.slf4j.api where a readme-bundles suggests that a Eclipse-GenericRequire is required for org.slf4j.impl.log4j12. Using Eclipse-GenericRequire results in a redirect to Require-Capability, but there is no overt Manifest editpr support and nothing appears the the Plugin Dependencies. Tests crash just as before since StaticLoggerBinder is not on the classpath.

Require-Capability seems to only work for some class-loaders. In some case the failure is CNFE. If a copy of org.slf4j.impl.log4j12 is provided as a plugin library, similar failures are due to two classes to choose from.

Googling for help, Bug 520754, suggests that m2E had a pretty torrid time.

Without a helpful example of how this can actually work, this is kicked into the very very long grass.
Comment 3 Christoph Laeubrich CLA 2022-01-26 08:02:39 EST
I'm must confess I do not fully understand the issue here. It seems some components tightly integrate with log4j, but how it is supposed to ever be logged to the eclipse log, most likely to some other tightly integrated stuff and so on.

So the very first step would be, to trow away log4j for *one* bundle and replace it with a package import for slf4j (choose the lower bound to be the current slf4j API version, e.g. 1.7.30 or what ever is 'current'):

org.slf4j;version="[1.7.0,2.0.0)"

the obtain loggers the following way (FQN just for clarity):

org.slf4j.Logger l = org.slf4j.LoggerFactory.getLogger(name/class)

now you are fine from the *producer* side.

If you like to get your log-output you have two choices:

a) include the simplelogger[1] fragment and you will get it to system.out should be sufficient for some initial testing
b) use any binding (e.g logback, slf4j, ...)
c) redirect it to the OSGi Log binding[2] (you should see thin in the eclipse/console log then) but it it not in Orbit see Bug 558556 


[1] https://www.slf4j.org/api/org/slf4j/impl/SimpleLogger.html
[2] https://github.com/osgi/slf4j-osgi
Comment 4 Ed Willink CLA 2022-01-26 10:55:53 EST
The problem is that OCL is a downstream project. If OCL declares SLF4J, that definition conflicts with an upstream definition from the platform/EMF/UML2/Xtext. If OCL does not declare it, JUnit tests bomb.

It seems to me that it is the platform that must declare SLF4J for at least the IDE, and preferably in a way that standalone usage can also exploit.

Whatever, a tutorial with relevant examples is needed, not just a study list.
Comment 5 Christoph Laeubrich CLA 2022-01-26 11:02:38 EST
(In reply to Ed Willink from comment #4)
> The problem is that OCL is a downstream project. If OCL declares SLF4J, that
> definition conflicts with an upstream definition from the
> platform/EMF/UML2/Xtext. If OCL does not declare it, JUnit tests bomb.
> 
> It seems to me that it is the platform that must declare SLF4J for at least
> the IDE, and preferably in a way that standalone usage can also exploit.
> 
> Whatever, a tutorial with relevant examples is needed, not just a study list.

Tutorial for slf4j[1]??? Or Tutorial for "(not) understanding platform eco-system in 365 days"?

I can help with anything related OSGi, SLF4J, SLF4J bindings, Java discussions but have no clue what OCL using SLF4J bombs out JUnit because it conflicts with upstream means ... maybe an example gerrit with a single class changing to slf4j would do more than a thousand words...

[1] https://www.slf4j.org/manual.html
Comment 6 Ed Willink CLA 2022-01-26 14:10:42 EST
Tutorial/example for how to
- configure SLF4J for platform IDE
- configure SLF4J for platform standalone
- configure SLF4J for downstream project IDE
- configure SLF4J for downstream project standalone
Comment 7 Christoph Laeubrich CLA 2022-01-26 23:21:46 EST
(In reply to Ed Willink from comment #6)
> Tutorial/example for how to
> - configure SLF4J for platform IDE
> - configure SLF4J for platform standalone
> - configure SLF4J for downstream project IDE
> - configure SLF4J for downstream project standalone

SLF4J is an API and do not need any configuration. On the top-level (e.g. EPP/RCP-Product) you have too choose a binding and depending on the binding you can configure the logging.

e.g. slf4j-osgi (no configuration required, this is what Xtext aims to)
 https://github.com/osgi/slf4j-osgi (see Bug 558556 to get it into Orbit)

or you use simplelogger (no configuration required, or configured through system properties:
https://www.slf4j.org/api/org/slf4j/impl/SimpleLogger.html
Comment 8 Ed Willink CLA 2022-01-27 01:00:00 EST
(In reply to Christoph Laeubrich from comment #7)
> SLF4J is an API and do not need any configuration. On the top-level (e.g.
> EPP/RCP-Product) you have too choose a binding and depending on the binding
> you can configure the logging.

Choosing a binding and configuring the logging seems precisely like a configuration. It may only be a couple of lines but until they are right it's broken.
 
> e.g. slf4j-osgi (no configuration required, this is what Xtext aims to)
>  https://github.com/osgi/slf4j-osgi (see Bug 558556 to get it into Orbit)

Xtext is a downstream project that facilitates further downstream projects so if Xtext solves the problem, whatever Xtext recommends is probably what OCL etc will need to do.
Comment 9 Christian Dietrich CLA 2022-01-27 01:14:29 EST
we we at Xtext have EXACT the same problems. even worse. we also have standalone modes that need a choice for configuration and binding. also we also have limited capactiy and that limited capacity (me) has zero slf4j knowledge
Comment 10 Christoph Laeubrich CLA 2022-01-27 01:22:52 EST
@Ed + @Christian : if you don't like to move, no problem. But I really can't believe given the projects to maintain, that SLF4J is any "magic" to you. And if I wonder how you even get log4j working then?

So what are we talking about? SLF4J API is in Orbit (or you can request never versions if desired) and AFAIK already part of Simrel.

Choosing a binding is just a matter of adding a suitable binding fragment, so you should be familiar with that as well.

As mentioned above, simply choose slf4jsimple for the sake of getting it bootstrapped and you are fine.

Negotiation on a default-binding shipped with eclipse-ide could be another task. Maybe as simple as choosing slf4j-osgi and simply get everything in the standard eclipse-log ...
Comment 11 Christian Dietrich CLA 2022-01-27 01:31:12 EST
i have "inherited" all the code.
Comment 12 Christian Dietrich CLA 2022-01-27 01:32:02 EST
and i am the guy who gets all the fallout and blame if something brakes. this makes me hate open source
Comment 13 Ed Willink CLA 2022-01-27 01:35:56 EST
Exactly. To someone who understands SLF4J, it may take only a few minutes to provide the few lines of declarations. But probably at least a day to configure and test, IDE and standalone, JUnit and Jenkins/Tycho with backward install compatibility to Oxygen. NB I have tests that register a custom TestAppender to ensure that the expected logs are produced and that unexpected logs fail.

I spent half a day and gave up. SLF4J is a probably powerful new capability that we overstretched developers do not have time to become expert in. We need good examples not reading lists.

A working example can be studied and gradually evolved to suit a different requirement.

(Log4J works because it mostly self-configures, and was part of the code base before I started well over ten years ago. I have had the occasional bad day trying to ensure that a not-configured diagnostic goes away in some Xtext test configurations.)

For SLF4J I couldn't even figure out what I needed in which MANIFEST.MF. This might be because there are missing bits in Orbit. Certainly there were no examples.
Comment 14 Christoph Laeubrich CLA 2022-01-27 01:49:58 EST
(In reply to Ed Willink from comment #13)
> I spent half a day and gave up. SLF4J is a probably powerful new capability

Now you are kidding aren't you? The first release of SLF4j was Dec, 2006 slf4j (if I found out correctly) dates back to Nov, 2005 .. se yeah its "quite new"

> that we overstretched developers do not have time to become expert in. We
> need good examples not reading lists.

Sorry but this is hilarious. Do do not need to become an "expert" to use SLF4J I already describe all you need to do do use it.

That you have chosen to support even ancient eclipse versions for free is nothing to blame on SLF4J


> A working example can be studied and gradually evolved to suit a different
> requirement.

As mentioned above you can start right now, first three examples when I search for "slf4j eclipse":

https://www.vogella.com/tutorials/EclipseLogging/article.html#slf4j-in-eclipse-applications

https://www.tutorialspoint.com/slf4j/slf4j_environment_setup.htm

there is even an Eclipse plugin for that:

https://marketplace.eclipse.org/category/free-tagging/slf4j


> (Log4J works because it mostly self-configures, and was part of the code
> base before I started well over ten years ago. I have had the occasional bad
> day trying to ensure that a not-configured diagnostic goes away in some
> Xtext test configurations.)


> For SLF4J I couldn't even figure out what I needed in which MANIFEST.MF.
> This might be because there are missing bits in Orbit. Certainly there were
> no examples.

I already gave you a line you simply need to copy to your manifest ...

Orbit provides numerous slf4j artifacts:
https://download.eclipse.org/tools/orbit/downloads/drops/R20211213173813/
Comment 15 Dirk Fauth CLA 2022-02-03 06:05:13 EST
Hi all,

just a few points (without additional emotions to the discussion):

1. Starting to use SLF4J is pretty simple. IIRC the slf4j.api is even part of the platform already. Simply adding org.slf4j to the imported packages of your plug-ins should work. Otherwise there is a more current version available in Orbit.

2. Migrating to SLF4F can be some work, the API is a bit different. But SLF4J provides a migration tool that could help
https://www.slf4j.org/migrator.html

That's it for development IIRC. The next step is the runtime. There you need to consider two aspects:

1. Support logging of third-party libraries.
Not every library developer shares the SLF4J usage and uses the logging library he or she favours. This can be leveraged by slf4j bridges. They actually implement the API of other logging frameworks and forward them to the SLF4J API. This is actually a cool feature, as any logging can be redirected to use a single logging mechanism.

2. Perform logging
In the end there needs to be a logging implementation. The native SLF4J API implementation is Logback (which is also available via Orbit). If you want to use another logging framework like Log4j 2.x or whatever, you need the corresponding SLF4J binding. That is the implementation of the SLF4J API that uses the respective Logging Framework API.

Now the more complicated topic could be the extension of a logging framework, e.g. the implementation of a custom appender. This will always be dependent on the logging framework that is actually used. I would not be aware of a generic solution for this using the SLF4J API. That means in that area you will stay dependent on the framework you use for logging. In case of the testing scenario mentioned, well stay with Log4j 1.x or implement it with another framework, as it is nothing you ship productively as far as I understood. Same with OSGi fragments that contain logging configurations. They are related to the logging framework they target.

So in short:
For development of plug-ins that you want to ship to customers, use SLF4J API as it also makes it easier for adopters that need to create their own runtimes to choose the logging they favour.
For your standalone runtimes, decide which logging framework you want to use and ensure you have a loggging impl and the necessary bridges and if necessary a binding included.
For custom log extensions, like custom log appender, filter, etc, double check if they are necessary (I personally would not use a logging framework to verify unit tests, but that is my opinion). If they are necessary, ensure that they match the runtime where they are executed. In the test scenario, you are in control of what library is used in the end.

I hope that helps. Let me know if you need some more information.
Comment 16 Ed Willink CLA 2022-02-03 06:44:07 EST
Thanks for the detail.

If I understand correctly: 

For test plugins, carry on unchanged adding a 'bridge' so that the test logging framework provides the SLF4J backend.

For deliverable plugins, switch to SLF4J, which given the trivial idiomatic log4j should be a such a simple migration that the trade-off between learning to use a migration tool and brute force may favour brute force.

If you can reference some (non-platform) Eclipse plugin that already uses SLF4J in recommended fashion, it should be easy to emulate it.

I'm not clear about the regular backend. Unless the platform providss it, presumably OCL must wait until Xtext or EMF provides it.

(For testing, the custom test appender is mostly a negative test - fail if a log message occurred, which seems like a good test functionality.)
Comment 17 Dirk Fauth CLA 2022-02-03 07:34:29 EST
(In reply to Ed Willink from comment #16)
> Thanks for the detail.
> 
> If I understand correctly: 
> 
> For test plugins, carry on unchanged adding a 'bridge' so that the test
> logging framework provides the SLF4J backend.

My personal opinion, no. First, logging in tests is considered bad practice. If you think of running your tests on the server, what additional information do you expect to find in the logs. If there is an error you have to run it again locally and debug. Of course it always depends on your use cases, and I don't want to blame anybody. But I typically do not use logging in test cases. I use assertions with meaningful error messages if things are not as they should be.
And also you use a custom appender, which only works with Log4J as logging framework. No bridge will cover that.

> For deliverable plugins, switch to SLF4J, which given the trivial idiomatic
> log4j should be a such a simple migration that the trade-off between
> learning to use a migration tool and brute force may favour brute force.

IIRC the migration tool was quite straight forward. It is a Swing based application and you simple set the folder to work on. It will basically change the import statements and the creation of a logger instance. Not sure anymore if it also replaces the logging calls themselves. But out of experience, the most annoying thing in the migration was the update of the import and the instance creation. ;)

> If you can reference some (non-platform) Eclipse plugin that already uses
> SLF4J in recommended fashion, it should be easy to emulate it.

You can have a look at NatTable. I moved to SLF4J with the 2.0.0 release. For simplicity I use the simple binding, that actually only prints to the console. If you use Logback or another logging framework + bridge it should also work.

https://git.eclipse.org/c/nattable/org.eclipse.nebula.widgets.nattable.git/

> I'm not clear about the regular backend. Unless the platform providss it,
> presumably OCL must wait until Xtext or EMF provides it.
> 
> (For testing, the custom test appender is mostly a negative test - fail if a
> log message occurred, which seems like a good test functionality.)

To be honest, I disagree. But of course I don't know your system under test and if you really want to test the logging functionality. But typically a log statement is a result of an error or an additional information. As a result of an error, it needs to be reflected somehow in a state, or even a non-changed state. That said, a test should verify such a state, not if a log statement was written or not. The test on a log statement or a non written log statement can be easily faked. Or you get false positives because your setup changes. But as I said, I don't know your project and what you are testing. Maybe it is the only way for you, as the state is not reachable. But typically tests based on logging are not a very solid solution.
Comment 18 Christoph Laeubrich CLA 2022-02-04 02:46:45 EST
(In reply to Ed Willink from comment #16)
> If you can reference some (non-platform) Eclipse plugin that already uses
> SLF4J in recommended fashion, it should be easy to emulate it.

JGit uses slf4j as well