/gist:0811d39d8264dcf881dc Secret
Created
October 16, 2012 15:10
-
-
Save magnet/0811d39d8264dcf881dc to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[13:45] <mart> so my question is really about what the aim of the proposal is. I'm wondering if you have a specific example of something that can't be implemented with the current design? | |
[13:46] <magnet_> no there is nothing I cannot do today in terms of functionality | |
[13:46] <magnet_> but there are things I can't prevent SLF4J to do | |
[13:46] <mart> I see. | |
[13:47] <mart> Do you know when/why slf4j stopped using fragment bundles for the impl? | |
[13:47] <magnet_> I know it did a few months ago looking at the archives | |
[13:48] <magnet_> it's all about making sure that there is a StaticLoggerBinding *before* any client has a chance to call LoggerFactory.getLogger() the first time | |
[13:48] <magnet_> the first call will trigger the loading of the static binding, so the class has to be available at that time | |
[13:48] <mart> and the impl bundle may not be resolved at that time? | |
[13:49] <magnet_> they cache the static binding to avoid doing it over and over | |
[13:49] <magnet_> if it's not here the first time, it will default to a no-op logger | |
[13:49] <magnet_> so the impl bundle must be resolved before the first call | |
[13:50] <mart> Suppose the impl bundle is available at container startup, can that happen? | |
[13:50] <magnet_> it can be installed before the API bundle, but they need each other to be "resolved" | |
[13:50] <mart> Just asking to check my understanding, here. | |
[13:51] <magnet_> the API bundle has Import-Package on org.slf4j.impl (e.g in LogBack) | |
[13:51] <magnet_> and the IMPL has Import-Package on org.slf4j (to implement the ifaces) | |
[13:51] <magnet_> it's a cyclic bundle dependency through package imports, and it's an anti-pattern | |
[13:51] <magnet_> that's why I want to make it optional | |
[13:51] <mart> so with that fragment bundle solution, both have to resolve at the same time, which (it seems to me) would mean that the api can't initialise in a state without an impl. | |
[13:52] <magnet_> you can't force the fragment to be present | |
[13:52] <magnet_> there is really no reason to make it a fragment | |
[13:53] <mart> ok, I understand it's not osgi-ish at all. But I'm trying to understand if/how it fails. | |
[13:54] <mart> presumably, the api bundle won't resolve without a fragment, and then the bundle that uses api won't resolve either? | |
[13:54] <magnet_> mhh just so I'm sure, what do you put in that fragment? The static binding system? The impl, :) | |
[13:55] <mart> yep, I think that's how it was. | |
[13:56] <magnet_> well there are several downsides with fragments: there's only one attempt at resolution (and no support for later install) and there can never be more than one fragment | |
[13:56] <magnet_> (iirc this was recently cleared in R5) | |
[13:56] <magnet_> s/cleared/made clear/ | |
[13:57] <magnet_> my problem is not so much how they package their bundles, but the fact that Slf4j has logic it shouldn't (as an API) | |
[13:57] <mart> ok, so if you wanted to change the impl, you'd have to re-resolve the api, and in turn, everything that used the api. | |
[13:57] <magnet_> yes you'd have to do a refresh | |
[13:58] <magnet_> in OSGi, ideally I'd like to be able to use multiple versions of the API concurrently, and for each of them multiple implementations | |
[13:58] <mart> isn't that possible now? | |
[13:58] <magnet_> (multiple implementations it's not that useful for logging, but it should be possible because I don't want to make assumptions on how ppl will use it) | |
[13:59] <magnet_> well the static binding limits things a bit but they can be worked around if you totally discard the static binding system and use services | |
[14:00] <magnet_> you still end up with a useless dependency and stateful singletons | |
[14:00] <mart> what's the useless dependency there? | |
[14:00] <magnet_> the Import-Package on org.slf4j.impl | |
[14:00] <magnet_> if I use services and discard static binding, that dep. is totally useless | |
[14:01] <mart> ok. | |
[14:01] <magnet_> my proposal is simply to take that custom binding system and put it in the JAR because it taints my runtime. | |
[14:02] <magnet_> 1) I don't want devs in my team to start using LoggerFactory.getLogger() by mistake | |
[14:02] <magnet_> 2) I already have a more powerful, dynamic binding system (the service registry + a component framework) | |
[14:02] <magnet_> 3) and I forgot my third point ;) | |
[14:03] <magnet_> most of all, it's almost nothing to cut it and let "legacy" users do it like they always did. | |
[14:03] <mart> my thoughts are that static loggers are so pervasive, it seems like a big change to remove them from the standard api. | |
[14:03] <magnet_> ah, the 3) point is: "I don't want to fork slf4j" | |
[14:04] <mart> I know that even if I start injecting loggers, I can be fairly sure that I have some dependency that assumes static loggers. | |
[14:04] <magnet_> exactly | |
[14:04] <magnet_> that's why I want to make a compatibility bundle | |
[14:04] <mart> yep. | |
[14:04] <mart> I understood that part. | |
[14:05] <magnet_> but on the other hand, if we don't do anything because some code depends on it, all projects end up stagnating | |
[14:06] <mart> a concern I have is that there are questions all over the internet where people fail to understand that right now, they need two jars for slf4j. I worry a third would exacerbate that. | |
[14:06] <magnet_> In my project, I'm trying to enforce, through that, the fact that only a component should be allowed to log. | |
[14:06] <magnet_> the idea is to still provide a all-in-one jar like many projects do | |
[14:06] <magnet_> OSGi folks will know to depend on slf4j-api-light | |
[14:07] <mart> so the current slf4j-api would retain LoggerFactory? | |
[14:07] <magnet_> I think it's better to aim at a backwards compatible API jar that is all-in-one, and make new "lighter" bundles | |
[14:07] <magnet_> yes, probably, though I'd like to deprecate it and move it to another package | |
[14:08] <magnet_> (to have a route for backwards compat. without split packages) | |
[14:10] <mart> One thing I don't like is that it forces changes on people who aren't using OSGi (which is most people). | |
[14:10] <magnet_> I hoped to start a discussion (like this one) with my proposal | |
[14:12] <mart> Well, I hope the things you'll see me struggling with will help you with convincing people. | |
[14:12] <magnet_> If you use that all in one bundle, your only change would be a deprecation warning, and just changing your import line. I agree it's not that benign... | |
[14:13] <magnet_> I hope too :). I'm not sure anything will happen at all, but you never know. Also, if it can make other library designers avoid the same mistakes..;) | |
[14:13] <magnet_> It's too bad the Logger/MarkerFactory classes are in org.slf4j | |
[14:13] <magnet_> if they were in another package the change would be entirely transparent | |
[14:14] <magnet_> oh, but that's a nice idea | |
[14:14] <magnet_> instead of moving them, we could move the API instead | |
[14:14] <mart> There are other ways to enforce that a client doesn't use the LoggerFactory, for example, a checkstyle or findbugs config. I wonder whether the downsides of such an approach would outweigh changing the api. | |
[14:14] <mart> "move the api"? | |
[14:15] <magnet_> we could move ILoggerFactory / IMarkerFactory to org.slf4j.api | |
[14:15] <magnet_> make the existing versions implement those | |
[14:16] <magnet_> the real problem that makes the change not backwards compatible is the split package problem. | |
[14:16] <mart> hmm. trying to imagine. | |
[14:16] <magnet_> that's another way to solve it, but it's not perfect either. | |
[14:17] <mart> So the split-packages trick could be documented on the slf4j website. | |
[14:17] <mart> I agree it's not ideal, but it's an interesting alternative. | |
[14:18] <magnet_> yes, and it's nothing for the next version of LogBack or other bridges to implement this API instead | |
[14:18] <magnet_> (as in, clients would not notice) | |
[14:18] <mart> By that I mean that no solution (short of a time machine) is ideal, so we're discussing least bad options. | |
[14:19] <magnet_> by the time any solution is accepted, there may be a time machine ;) | |
[14:19] <mart> :D | |
[14:19] <magnet_> I like that solution better too | |
[14:19] <mart> I've seen Bill and Ted's Excellent Adventure. I'd totally take Beethoven to the mall. | |
[14:20] <magnet_> mhh, never watched it | |
[14:20] <mart> It was excellent, but I expect it's dated terribly. ;) | |
[14:20] <magnet_> but if they go meet Beethoven I will :) | |
[14:20] <mart> So, anyway, ILoggerFactory and IMarkerFactory move to org.slf4j.api ... | |
[14:21] <mart> what happens to LoggerFactory, in this case? | |
[14:21] <magnet_> yes, and implementations & bridges (most of them being controlled by ceki) update to those APIs | |
[14:21] <magnet_> well LoggerFactory doesn't move | |
[14:21] <mart> ok. | |
[14:21] <magnet_> it's just that we provide other packaging for DI users | |
[14:22] <magnet_> we keep the same slf4j-all-in-one JAR | |
[14:22] <mart> Ah, so the osgi bridge would just depend on org.slf4j.api? | |
[14:22] <magnet_> and we also provide a packaging without org.slf4j | |
[14:22] <magnet_> yes | |
[14:22] <magnet_> and the light API bundle woudln't depend on org.slf4j.impl anymore | |
[14:23] <magnet_> ideally we'd deprecate Logger, ILoggerFactory and IMarkerFactory but we're not forced to. | |
[14:23] <mart> I see, so Logger would move too? | |
[14:23] <mart> to org.slf4j.api? | |
[14:23] <magnet_> they will become empty ifaces implementing their counterpart in org.slf4j.api | |
[14:23] <magnet_> yes it has to | |
[14:24] <mart> ok, I'm following now. | |
[14:24] <magnet_> I understand it's not cool to have a deprecated type in hundreds of projects | |
[14:24] <magnet_> (even when the solution is just changing an import) | |
[14:25] <mart> you'd be amazed at how many people don't know sed. :) | |
[14:25] <magnet_> the question is, would you rather have Logger or LoggerFactory deprecated ; | |
[14:25] <magnet_> there's also a migrator project in slf4j that does the update from log4j and JCL | |
[14:25] <mart> gah. all that code using static loggers is using both. | |
[14:25] <magnet_> the migrator could be updated for that change | |
[14:26] <magnet_> there could also be SLF4J version 2.0.0 and people happy with the 1.x stream would stay there until ready | |
[14:26] <mart> problem then is that people need to figure out what's compatible with what. | |
[14:27] <magnet_> yes, i know. people don't version their dependencies neither at build or runtime, then software vendors are stuck | |
[14:27] <mart> I guess if you can always just drop in the compat jar, then it's not *so* bad. | |
[14:27] <magnet_> yes, and that jar can stay around forever | |
[14:28] <mart> so, would your project end up using three bundles: the (reduced) api; an osgi bridge and a backend? | |
[14:29] <magnet_> yes, for my setup i'd have: the light API, a bridge taking from the OSGi LogService to SLF4j, Logback as an Impl, and a smart iPojo injector for my components | |
[14:29] <magnet_> (smart injector because loggers would be removed if the iloggerfactory service is unregistered) | |
[14:30] <mart> let's list properties that may or may not hold of any solution: | |
[14:31] <mart> * it may (not) require a refresh of client bundles when the backend is updated. | |
[14:32] <mart> * it may (not) allow enforcement of "no LoggerFactory.getLogger calls" by setting dependencies/imports | |
[14:33] <mart> * it may (not) require deprecating classes/interfaces used by non-OSGi apps/libs | |
[14:34] <mart> * it may (not) allow the impl package to be a non-exported package. | |
[14:35] <mart> am I missing anything that we can use to evaluate a solution? | |
[14:35] <magnet_> mhh | |
[14:37] <magnet_> looks like you captured it | |
[14:38] <mart> something we haven't discussed is whether the LoggerFactory could be left as is, but return a proxy Logger, that uses the currently installed backend. | |
[14:39] <magnet_> but how would that proxy Logger know the backend has changed? | |
[14:39] <mart> BundleTracker? I'm thinking something that'd only be used in an OSGi environment. | |
[14:39] <magnet_> that would imply creating new SPI hooks in a non-OSGi environments | |
[14:39] <magnet_> ha, but then would you have OSGi specific code in LoggerFactoryN | |
[14:39] <magnet_> ? | |
[14:40] <mart> I was more thinking of an impl that tracked other impl bundles. | |
[14:41] <magnet_> and expose API in LoggerFactory to update the Logger proxy? | |
[14:41] <mart> * it may (not) require OSGi users to use split packages | |
[14:41] <mart> (missed one) | |
[14:42] <mart> no, no. | |
[14:42] <mart> The client just gets back an instance of the Logger interface, right? | |
[14:42] <magnet_> yep | |
[14:43] <mart> Suppose it's a proxy logger that updates when the backend is updated. | |
[14:43] <magnet_> yes but that means there is a special OSGiProxyLogger class somewhere that's using a BundleTracker or something | |
[14:44] <mart> let's say in a bundle called slf4j-proxy that contains a static binding. | |
[14:44] <magnet_> but LoggerFactory is already in the API, how would it be "overriden"? | |
[14:45] <magnet_> or would there be a new SPI class to provide ProxyFactories? | |
[14:45] <mart> suppose LoggerFactory doesn't change, and we just implement a static binding that returns proxy loggers | |
[14:45] <magnet_> hi ceki :) | |
[14:45] <ceki> hi | |
[14:45] <mart> heh, hi. | |
[14:46] <magnet_> mart, so LoggerFactory would just try to load a class by name? like it does with StaticLoggerBinding? | |
[14:46] <mart> yup. | |
[14:46] <magnet_> isn't that repeating the same mistake? ;) | |
[14:46] <ceki> is there a transcipt of your discussion? | |
[14:46] <magnet_> ceki, Arbalest | |
[14:47] <magnet_> it's the Eclipse logger, so I guess its logs are available somewhere | |
[14:47] <mart> magnet_: it's fixing one of our OSGi problems (the refresh problem), and not changing any api. | |
[14:48] <mart> magnet_: which problem do you most want to fix? | |
[14:48] <magnet_> mart, the dependency API -> impl. | |
[14:49] <magnet_> that solution adds a new dependency on API -> slf4j-proxy | |
[14:50] <mart> ok. it's not a very osgi-ish design. | |
[14:50] <mart> I'm still not sure exactly what problem that causes that creates the most pain for you. | |
[14:51] <mart> I get that "it's not the way we like to do things in OSGi", but I'm trying to understand which consequence of that causes most difficulty. | |
[14:51] <magnet_> I get your point | |
[14:53] <ceki> Arbalest ~sendlog | |
[14:53] <ceki> Arbalest, ~sendlog | |
[14:55] <magnet_> mart, I'm not blocked at what I'm trying to do. I'm trying to propose something that works better (or is cleaner) for OSGi users, and works the same for everyone else. | |
[14:56] <magnet_> that was my intro: I'm choosing a framework for a new OSGi project, so I'd rather avoid compromises so early ;) | |
[14:57] <magnet_> ceki, did you succeed at getting the logs? | |
[14:57] <ceki> nope | |
[14:57] <magnet_> do direct connections work for you? | |
[14:57] <ceki> i think so | |
[14:58] <magnet_> mhh maybe they don't for me ;) | |
[14:58] <ceki> i just conencted with Arbalest | |
[14:58] <magnet_> we recently moved at work and I don't how they set the firewall up | |
[14:58] <magnet_> ok | |
[14:59] <magnet_> maybe it will work from me to you | |
[14:59] <mart> magnet_: I do see the motivation. I agree that for OSGi, the factories should probably have been in a separate package. But it seems like a big change for everyone, and I'd think people would expect a very clear explanation of why it was made. | |
[15:00] <magnet_> did you get the request? | |
[15:00] <ceki> yes | |
[15:00] <ceki> don't know that to do with it | |
[15:00] <magnet_> no accept button? :) | |
[15:00] <mart> should we just gist it? | |
# after gist | |
<ceki> Once slf4j-api binds, it's irreversible | |
<magnet_> yes and no :) | |
<ceki> what else? | |
<mart> ceki: In OSGi, it's possible to 'refresh' bundles. You could change the logging backend, refresh everything, and use the new backend. | |
<magnet_> slf4j already works with OSGi, but the idea is it could work best if we used OSGi's binding system (services + a adhoc component framework) instead of slf4j's static bindings | |
<magnet_> so it does "too much" for OSGi -- and just enough for plain old Java | |
<mart> (So, no, it's not irreversable, but yes, you have to refresh everything that uses slf4j's to change it.) | |
<magnet_> i'm not sure how the refresh would behave with the LoggerFactory though | |
<magnet_> it refreshes the package wirings, but the local static state isn't supposed to just vanish | |
<ceki> i am still reading the logs | |
<mart> magnet_: Isn't the static state wiped when refreshing the other bundles? | |
<magnet_> mart, not sure, I would have to test | |
<magnet_> (I don't think so) | |
<mart> my understanding was that the bundle was stopped; re-resolved; and restarted. | |
<magnet_> yes | |
* kensanata (~user@fsf/member/kensanata) a rejoint #osgi | |
<magnet_> yes you're right. | |
<magnet_> the old static should be gc'd | |
<mart> which should include the loggers for the old slf4j impl. | |
<magnet_> yes | |
<ceki> martin has captured many of the questions i had | |
<ceki> questions/remarks | |
* kensanata est parti (Remote host closed the connection) | |
<magnet_> yep those were good questions, I understand there is reluctance to anything that endangers backwards compat for most users | |
<magnet_> but I also think we can be compatible and improve things a bit in terms of modularity :) | |
<ceki> i'll concede off the bat that slf4j modularity sucks | |
<mart> What are the advantages/drawbacks of leaving everything as is, but creating a new bundle that contains a subset of those in slf4j-api (including Logger)? | |
<mart> I guess a drawback is that things that depend on org.slf4j wouldn't be clear on whether they were depending on the reduced API or the full API. | |
<ceki> indeed | |
<magnet_> yes but tons of projects do that. | |
<magnet_> people spend 5 minutes getting the right dependency in their POM and then forget about it | |
<magnet_> the problem is when the contents of the artifacts change between versions | |
<magnet_> thats why I proposed to keep the same artifactId for the "all in one" JAR | |
<ceki> what would be in the all in one jar? | |
<magnet_> slf4j-light-api + slf4j-static-binding | |
<mart> which is the current slf4j-api, with some classes moved to a different package? | |
<ceki> so there would be slf4j-simple-all.jar, slf4j-log4j-all.jar, slf4j-jdk14-all.jar, etc... ? | |
<magnet_> yes, moved + a redirection class (that should be deprecated in an ideal world) | |
<magnet_> if you do still jdk14 builds yes that's going to multiply. | |
<mart> There wouldn't need to be one for each backend, though, right? | |
<magnet_> you can also end support of jdk14 after slf4j 2.0.0 considering it's been EOL'd years ago ;) | |
<mart> magnet_: Kindle is still 1.4, I think. :) | |
<mart> ish. | |
<magnet_> damn :) | |
<ceki> jdk14 stands for jul not jdk14 | |
<mart> ah, yes. sorry | |
<ceki> jul = java.util.logging | |
<magnet_> yes | |
<magnet_> so.. no | |
<magnet_> there wouldn't be -all packages for those | |
<mart> When magnet_ says "all in one", I don't think he means the logging impl in there too. | |
<magnet_> yes only api side, not impl | |
<mart> "all in one" (here) means Logger and LoggerFactory | |
<mart> et. al. :) | |
<magnet_> a whiteboard would be nice :) | |
<ceki> you would separate the interfaces from static binding code | |
<magnet_> ceki, ideally, yes: impl should provide their static bindings aside | |
<magnet_> yes | |
<ceki> this would ge useful because? | |
<mart> oh, I misunderstood. | |
<ceki> s/ge/be/ | |
<magnet_> ceki, because unfortunately OSGi doesn't support split packages | |
<magnet_> it means that you can't (or must hack around if) have two bundles exporting the same package | |
<magnet_> if we want to make the static binding code optional, and still need the interfaces, we must separate the packages so they end up in two bundles | |
<magnet_> those who want to use static binding still can | |
<magnet_> and those who don't can use the built-in mechanisms in OSGi (dynamic binding et all) | |
<magnet_> or not only OSGi: Guice, Spring, Plexus/Sisu for Maven, whatever |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment