Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No logging framework implementation when enabling proguard on Android #126

Closed
grill2010 opened this issue Nov 23, 2019 · 21 comments
Closed
Labels

Comments

@grill2010
Copy link

grill2010 commented Nov 23, 2019

Hi, I'm using tinylog version 2.0.0 on Android and it worked great. However I recently released my new app and I found out that the log file never gets created. So I started to investigate the issue. What I found out is that as soon as I enable proguard on my release build I receive following output on the logcat when I log something

LOGGER WARN: No logging framework implementation found in classpath. Add tinylog-impl.jar for outputting log entries.

My tinylog.properties file looks like this

writer=rolling file
writer.file=/data/data/test.grill.com/files/test_logs/test_log.txt
writer.level=info
writer.policies=size: 5mb
writer.format={date: HH:mm:ss.SSS} [{thread}] {level}:\n{message}

and it is located in my resources folder. Everything is working when I'm not enabling proguard. Are there some proguard rules which needs to be added when using tinylog with proguard?

Edit: seems that the ServiceLoader could not get anyResourses

classLoader.getResources(name);

returns an empty Enumeration when enabling proguard.

@pmwmedia
Copy link
Member

The problem is that tinylog cannot find TinylogLoggingProvider and other classes, which are loaded by ServiceLoader, because Proguard renames all classes. If configure Proguard to keep all tinylog class names, logging should work again:

-keepnames public class org.tinylog.**

@grill2010
Copy link
Author

Yes I know this, thank you for the information. I was already playing arround with

keepdirectories
keeppackagenames
keep enum
keep class
keep interface

but I didn't try yet with keepnames. Will try it when I'm at home. Thank you for the info.

@pmwmedia
Copy link
Member

@grill2010 Your are welcome! Please let me know if it works for you :-)

@grill2010
Copy link
Author

grill2010 commented Nov 25, 2019

Hmm, I'm not able to make it work. I think it should work but still I get the same error.
I know my proguard-rules files work because I have other rules in it which are working. I tried all sort of crazy rules now, here are a few examples

-keep class org.tinylog.** { ; }
-keep interface org.tinylog.
* { ; }
-keep enum org.tinylog.
* { *; }

-keepdirectories **tinylog**
-keepdirectories org.tinylog
-keepdirectories org.tinylog
-keepdirectories org.tinylog.**
-keepdirectories org.tinylog**

-keeppackagenames **tinylog**
-keeppackagenames org.tinylog
-keeppackagenames org.tinylog
-keeppackagenames org.tinylog.**
-keeppackagenames org.tinylog**

-keepnames class org.tinylog.*
-keepnames class org.tinylog.**
-keepnames class org.tinylog.** {*;}

-keepclasseswithmembers class org.tinylog.** {*;}

Nothing seems to be working, for now I do not have any more ideas.

@pmwmedia
Copy link
Member

@grill2010 Can you provide a minimal example project that reproduces the issue? I will analyze the cause.

@grill2010
Copy link
Author

Sure, will try to provide some example project tomorrow.

@grill2010
Copy link
Author

Faster than expected, here is a standard Android example with tinylog. I have included the pro guard rules and the build.gradle has minifying enabled. Same error occurs in this project.
TinyLogExample.zip

@grill2010
Copy link
Author

grill2010 commented Nov 26, 2019

I've analyzed the apk of my example project and I found out that when I build the project with proguard enabled the folder services in the META_INF/services directory is missing completely.

APK compiled with proguard
APK compiled without proguard

Any ideas why this happens? I didn't dig very much into the tinylog project yet so I have no clue yet why this happens.

@pmwmedia
Copy link
Member

pmwmedia commented Nov 27, 2019

@grill2010 The only way, I found to keep the META-INF/services directory is to use the -dontshrink rule.

With these ProGuard rules, tinylog works well with your example project.

##---------------Begin: tinylog  ----------
-dontshrink
-keepnames interface org.tinylog.**
-keepnames class * implements org.tinylog.**
##---------------End: tinylog  ----------

However, I don't like using the -dontshrink rule as it will lead to bigger APK files. Currently I'm looking for a way to bypass it.

@grill2010
Copy link
Author

grill2010 commented Nov 27, 2019

Okay I see, interesting. I was also looking around on the Internet and what I found is that there were a lot of problems with the META-INF/services directory in regard to include it in the build apk and it seems somehow the problem still persists. It is somehow related to proguard and not gradle. But of course using dontshrink option is not ideal like you said...

Edit: The dontshrink removes unused resources and proguard thinks that these resource files are somehow not needed and simply removes them. Maybe because they are not referenced directly in the code but are accessed via the ClassLoader. There must be a way to tell proguard to not remove this files. Another way would be to create a direct pseudo reference somewhere in the code so that proguard does not remove them, but I've not tested it yet.

@pmwmedia
Copy link
Member

pmwmedia commented Nov 27, 2019

I found a workaround to tell ProGuard to keep the service files:

protected void onCreate(Bundle savedInstanceState) {
    ServiceLoader.load(LoggingProvider.class);
    ServiceLoader.load(Writer.class);
    ServiceLoader.load(Policy.class);

    super.onCreate(savedInstanceState);

    Logger.error("Test output");

    ...
}

ProGuard rules:

##---------------Begin: tinylog  ----------
-keepnames interface org.tinylog.**
-keepnames class * implements org.tinylog.**
-keepclassmembers class * implements org.tinylog.** { <init>(...); }
##---------------End: tinylog  ----------

I plan to add these ServiceLoader calls directly in tinylog 2.1 to make logging with tinylog for Android developers much more convenient when using ProGuard.

For tinylog 3, I'm experimenting with a builder concept for instantiation of logging providers, writers, and policies. Then, even no ProGuard rules nor any workaround will be required for tinylog. This will also solve #127.

@grill2010
Copy link
Author

Awesome. Thank you very much.
Suggestions for tinylog 3 sound good. If tinylog 2.0 is working correctly with the workaround that's good enough for me now. Looking forward to the next releases.

@pmwmedia pmwmedia added bug and removed question labels Nov 27, 2019
@pmwmedia
Copy link
Member

pmwmedia commented Nov 27, 2019

@grill2010 Could you test the attached JARs? They contain the workaround with the ServiceLoader.load() calls. You will only need the the three ProGuard rules from my last post.

tinylog-2.0-SNAPSHOT.zip

@grill2010
Copy link
Author

Sure I will test it when I have time and will let you know what are the results.

@Kameswari
Copy link

@pmwmedia
Hi, is this issue addressed in latest tiny log version? For me also, log file is not generated in release mode build. I added the below progaurd rules as you mentioned and upgraded the tiny log library to 2.1.2. But still log file is not generated.

##---------------Begin: tinylog ----------
-keepnames interface org.tinylog.**
-keepnames class * implements org.tinylog.**
-keepclassmembers class * implements org.tinylog.** { (...); }
##---------------End: tinylog ----------

if I set the debuggable option to true, then its working.

@pmwmedia
Copy link
Member

@Kameswari Are you able to reproduce this issue by using the official example project https://github.com/pmwmedia/tinylog-android-example?

@Kameswari
Copy link

@pmwmedia Your sample is working fine. Going through my code and analyzing where I did wrong. Will let you know after I figured out.

Thanks

@grill2010
Copy link
Author

@pmwmedia sorry for not getting back to you. I've forgotten to reply, shame on me. Your example was working fine and I'm also now using the newest version of tinylog in my applications with proguard and it works now without any workarounds.
@Kameswari maybe an error in the tinylog.properties file or created it in the wrong directory?

@Kameswari
Copy link

@grill2010 Thanks for the reply. I have used below properties and its working fine in debug version build. Also in release mode, if I set debuggable property as true, its working fine.

writer = rolling file
writer.format = {date:yyyy-MM-dd HH:mm:ss} {level}: {message}
writer.file = #{logs.folder}/MyLogs/log.{count}.txt
writer.charset = UTF-8
writer.policies = size: 1mb
writer.backups = 1

I have used same properties in Sample project and it worked fine in release mode too.

@Kameswari
Copy link

Kameswari commented Jul 16, 2020

@grill2010 @pmwmedia My mistake. I forgot that I am writing the logs only in debug mode. It's working fine. Thanks for your support.

@github-actions
Copy link

github-actions bot commented Oct 9, 2022

This closed issue has been locked automatically. However, please feel free to file a new issue.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Oct 9, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Development

No branches or pull requests

3 participants