[Bug 173] New: slf4j android: Android throws an IllegalArgumentException when Log Tag length exceeds 23 characters

http://bugzilla.slf4j.org/show_bug.cgi?id=173 Summary: slf4j android: Android throws an IllegalArgumentException when Log Tag length exceeds 23 characters Product: SLF4J Version: 1.5.x Platform: Other OS/Version: other Status: NEW Severity: blocker Priority: P1 Component: Implementations AssignedTo: slf4j-dev@qos.ch ReportedBy: lorecarra@gmail.com I don't know if the 23-characters long tag limitation has been removed in later releases, but, unfortunately, Android 1.1 has it. I think the tag length should be checked and the tag eventually trimmed in order to avoid incurring in this exception without having to change the application logging code. The check is performed into the native method android.util.Log.isLoggable() To reproduce the problem in Android 1.1: String ALLOWED_TAG = "abcdefghijklmnopqrstuvw"; String TOO_LONG_TAG = "abcdefghijklmnopqrstuvwxyz"; Log.i(ALLOWED_TAG, "blabla"); Log.i(TOO_LONG_TAG, "blabla"); -- Configure bugmail: http://bugzilla.slf4j.org/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- You are the assignee for the bug.

http://bugzilla.slf4j.org/show_bug.cgi?id=173 --- Comment #1 from Thorsten <thorsten.Moeller@unibas.ch> 2010-03-12 15:21:22 --- Lorenzo, since I currently do not have the resources available: would it be possible for you to test if this limitation of max 23 chars does exist in newer Android versions (1.5, 1.6, 2.0, 2.1) as well. It would be worth knowing this before creating a fix. Thanks, Thorsten -- Configure bugmail: http://bugzilla.slf4j.org/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- You are the assignee for the bug.

http://bugzilla.slf4j.org/show_bug.cgi?id=173 --- Comment #2 from Lorenzo Carrara <lorecarra@gmail.com> 2010-03-12 16:36:34 --- (In reply to comment #1)
Lorenzo,
since I currently do not have the resources available: would it be possible for you to test if this limitation of max 23 chars does exist in newer Android versions (1.5, 1.6, 2.0, 2.1) as well. It would be worth knowing this before creating a fix.
Thanks, Thorsten
I will surely check as soon as I can. Anyway, before submitting this bug I checked the code where the error is thrown in the android source repository trunk (the Android 2.1 platform code), and it's still there. I quote some code: In android/system/core/include/cutils/property.h: #define PROPERTY_KEY_MAX 32 In android/frameworks/base/core/jni/android_util_Log.cpp ... #define LOG_NAMESPACE "log.tag." ... if ((strlen(chars)+sizeof(LOG_NAMESPACE)) > PROPERTY_KEY_MAX) { -> THROW EXCEPTION: Log tag X exceeds limit of (PROPERTY_KEY_MAX - sizeof(LOG_NAMESPACE) characters Hope this helps, when I'll reach an emulator I'll check with the other versions of the platform. Bye! Lorenzo -- Configure bugmail: http://bugzilla.slf4j.org/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- You are the assignee for the bug.

http://bugzilla.slf4j.org/show_bug.cgi?id=173 --- Comment #3 from Thorsten <thorsten.Moeller@unibas.ch> 2010-03-12 17:02:09 --- (In reply to comment #2)
I will surely check as soon as I can. Anyway, before submitting this bug I checked the code where the error is thrown in the android source repository trunk (the Android 2.1 platform code), and it's still there. I quote some code:
In android/system/core/include/cutils/property.h:
#define PROPERTY_KEY_MAX 32
In android/frameworks/base/core/jni/android_util_Log.cpp
... #define LOG_NAMESPACE "log.tag." ... if ((strlen(chars)+sizeof(LOG_NAMESPACE)) > PROPERTY_KEY_MAX) { -> THROW EXCEPTION: Log tag X exceeds limit of (PROPERTY_KEY_MAX - sizeof(LOG_NAMESPACE) characters
My conclusion of this is that the problem most likely does exist since 1.1 (up to 2.1). And, I guess the initial value "23" you gave is a typo and it is actually 32, correct?
Hope this helps, when I'll reach an emulator I'll check with the other versions of the platform. Exactly. Should be easily verifiable using the emulator.
-- Thorsten -- Configure bugmail: http://bugzilla.slf4j.org/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- You are the assignee for the bug.

http://bugzilla.slf4j.org/show_bug.cgi?id=173 --- Comment #4 from Lorenzo Carrara <lorecarra@gmail.com> 2010-03-12 17:07:41 ---
My conclusion of this is that the problem most likely does exist since 1.1 (up to 2.1).
And, I guess the initial value "23" you gave is a typo and it is actually 32, correct?
No it's not a typo: Android's internal logging framework prefixes log tags with the string defined in LOG_NAMESPACE (see previous comment), and the 32 characters limit refers to the prefixed string. So, being this namespace 8 chars long, the tag limit becomes 24 characters. I guess one more character goes as the C string terminator, so in the end we have 23 characters left in Java. -- Configure bugmail: http://bugzilla.slf4j.org/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- You are the assignee for the bug.

http://bugzilla.slf4j.org/show_bug.cgi?id=173 --- Comment #5 from Thorsten <thorsten.Moeller@unibas.ch> 2010-03-22 11:49:56 --- Do you agree that the fix merely truncates tag names longer than 23 characters, like so: private static final int MAX_TAG_LENGTH = 23; AndroidLogger(final String name) { // fix for bug #173: trim tag length in case it exceeds maximum length this.name = (name != null && name.length() > MAX_TAG_LENGTH)? name.substring(0, MAX_TAG_LENGTH) : name; } Any comments, proposals for a more advanced way on how to shorten tag names? -- Configure bugmail: http://bugzilla.slf4j.org/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- You are the assignee for the bug.

http://bugzilla.slf4j.org/show_bug.cgi?id=173 Thorsten <thorsten.Moeller@unibas.ch> changed: What |Removed |Added ---------------------------------------------------------------------------- Component|Implementations |slf4j-android -- Configure bugmail: http://bugzilla.slf4j.org/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- You are the assignee for the bug.

http://bugzilla.slf4j.org/show_bug.cgi?id=173 Thorsten <thorsten.Moeller@unibas.ch> changed: What |Removed |Added ---------------------------------------------------------------------------- Status|NEW |ASSIGNED -- Configure bugmail: http://bugzilla.slf4j.org/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- You are the assignee for the bug.

http://bugzilla.slf4j.org/show_bug.cgi?id=173 --- Comment #6 from Lorenzo Carrara <lorecarra@gmail.com> 2010-03-22 15:34:01 --- (In reply to comment #5)
Do you agree that the fix merely truncates tag names longer than 23 characters, like so:
private static final int MAX_TAG_LENGTH = 23;
AndroidLogger(final String name) { // fix for bug #173: trim tag length in case it exceeds maximum length this.name = (name != null && name.length() > MAX_TAG_LENGTH)? name.substring(0, MAX_TAG_LENGTH) : name; }
Any comments, proposals for a more advanced way on how to shorten tag names?
Yes that would solve the issue. The only problem is that patching AndroidLogger's constructor would result in creating a different logger for all the tags with the same first 23 chars (so, many loggers for the same trimmed tag). I've written a patch for org.slf4j.impl.AndroidLoggerFactory class that basically does the same thing but avoids this problem, this is how it works: - in getLogger, it checks the tag's length. If it's greater that 23 chars, it trims out the first part (which usually is the least significant, like a part of the package). - then it checks the loggerMap to see if that logger has already been created. - if there's no logger for that tag, it creates one and, if the tag has been trimmed, logs a warning about that. Then the new logger is mapped to the trimmed tag in loggerMap. This way only one logger is created, and the warning is logged just the first time it's used (when the logger is created), so the log doesn't get cluttered with "too long tag" warnings. The drawback is that the "too long" tags are trimmed every time getLogger is called for that logger, but that could be solved using a lookup map between long tags and corresponding trimmed ones. I've been using this patched version of slf4j in an Android project which uses an external library only using tags longer that 23 chars, and everything works perfectly. Patched code follows: /* * Created 21.10.2009 * * Copyright (c) 2009 SLF4J.ORG * * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package org.slf4j.impl; import java.util.HashMap; import java.util.Map; import org.slf4j.ILoggerFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * An implementation of {@link ILoggerFactory} which always returns * {@link AndroidLogger} instances. * * @author Thorsten Möler * @version $Rev:$; $Author:$; $Date:$ */ public class AndroidLoggerFactory implements ILoggerFactory { //ANDROID: log tag max length, according to Android sources private static final int TAG_MAX_LENGTH = 23; //ANDROID: internal logger, logs warnings for too long tags private static Logger internalLogger = null; private final Map<String, AndroidLogger> loggerMap; protected static Logger getInternalLogger() { if(internalLogger == null) { // internal logger name length must be below TAG_MAX_LENGTH, or it will go into an infinite loop internalLogger = LoggerFactory.getLogger("AndroidLoggerFactory"); } return internalLogger; } public AndroidLoggerFactory() { loggerMap = new HashMap<String, AndroidLogger>(); } //ANDROID introduced name length check /* @see org.slf4j.ILoggerFactory#getLogger(java.lang.String) */ public AndroidLogger getLogger(String name) { boolean isTooLong = false; String tooLongName = null; if(name.length() > TAG_MAX_LENGTH) { // remove the first part of the name, which usually is the least significant isTooLong = true; tooLongName = new String(name); name = name.substring(name.length() - TAG_MAX_LENGTH, name.length()); } AndroidLogger slogger = null; // protect against concurrent access of the loggerMap synchronized (this) { slogger = loggerMap.get(name); if (slogger == null) { if(isTooLong) getInternalLogger().info("Logger name " + tooLongName + " is too long, using " + name + " instead"); slogger = new AndroidLogger(name); loggerMap.put(name, slogger); } } return slogger; } } -- Configure bugmail: http://bugzilla.slf4j.org/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- You are the assignee for the bug.

http://bugzilla.slf4j.org/show_bug.cgi?id=173 --- Comment #7 from Thorsten <thorsten.Moeller@unibas.ch> 2010-03-23 16:45:07 --- Thanks for pointing out the problem of creating a different logger for all the tags with the same first 23 chars. I agree with you to do the check in the factory rather than at instantiation time of a logger. However, the patch you submitted has the famous double checked locking problem [1]: internalLogger is a static singleton variable. I have modified (and simplified) your patch and will push it to the SLf4J Android branch soon. [1] http://www.ibm.com/developerworks/java/library/j-dcl.html -- Configure bugmail: http://bugzilla.slf4j.org/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- You are the assignee for the bug.

http://bugzilla.slf4j.org/show_bug.cgi?id=173 --- Comment #8 from Lorenzo Carrara <lorecarra@gmail.com> 2010-03-23 17:08:44 --- Never thought about that kind of issue. I've learnt something, thanks! Anyway, seems to me that the logger creation code is always executed inside a synchronized block, isn't it? -- Configure bugmail: http://bugzilla.slf4j.org/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- You are the assignee for the bug.

http://bugzilla.slf4j.org/show_bug.cgi?id=173 --- Comment #9 from Thorsten <thorsten.Moeller@unibas.ch> 2010-03-23 17:19:20 --- Lucky you. Yes, you are right. Sorry, was a bit too fast. The problem cannot occur since a) the static code is invoked within instance code, b) and nowhere else, c) there exist only one instance of AndroidLoggerFactory at runtime, and d) is inside a synchronized block. As soon as there could be more than one instance of AndroidLoggerFactory, for instance, the problem could occur even with the synchronized block. -- Configure bugmail: http://bugzilla.slf4j.org/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- You are the assignee for the bug.

http://bugzilla.slf4j.org/show_bug.cgi?id=173 Wendell <wendell_temp_1234@comcast.net> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |wendell_temp_1234@comcast.ne | |t --- Comment #10 from Wendell <wendell_temp_1234@comcast.net> 2010-05-19 21:38:22 --- I ran into the same thing and created a fix that uses the more useful part of a full class name if possible: public class AndroidLoggerFactory implements ILoggerFactory { private static final int MAX_TAG_LENGTH = 23; private final Map<String, AndroidLogger> loggerMap; public AndroidLoggerFactory() { loggerMap = new HashMap<String, AndroidLogger>(); } /* @see org.slf4j.ILoggerFactory#getLogger(java.lang.String) */ public AndroidLogger getLogger(String name) { name = forceValidTag(name); AndroidLogger slogger = null; // protect against concurrent access of the loggerMap synchronized (this) { slogger = loggerMap.get(name); if (slogger == null) { slogger = new AndroidLogger(name); loggerMap.put(name, slogger); } } return slogger; } protected String forceValidTag(String tag) { if (tag.length() > MAX_TAG_LENGTH) { // try to do something expected // if there's a '.' in the tag, it probably came from a fully qualified class name // use the trailing end // extra character because we're going to remove the '.' String lastPart = tag.substring(tag.length() - MAX_TAG_LENGTH - 1); int dot = lastPart.indexOf('.'); if (dot >= 0 && dot != lastPart.length() - 1) { // return as much of the dotted path as will fit return lastPart.substring(dot + 1); } else { // no useful dot location, just take the beginning return tag.substring(0, MAX_TAG_LENGTH); } } else { return tag; } } } -- Configure bugmail: http://bugzilla.slf4j.org/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- You are the assignee for the bug.

http://bugzilla.slf4j.org/show_bug.cgi?id=173 Matt Brown <msbcode@gmail.com> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |msbcode@gmail.com --- Comment #11 from Matt Brown <msbcode@gmail.com> 2010-06-08 06:38:01 --- Hi, I noticed some comments up above questioning whether or not Android still has this behavior in later versions. I can confirm that in version 2.2 that an IllegalArgument is (still) thrown if the logger name is > 23 characters long. -- Configure bugmail: http://bugzilla.slf4j.org/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- You are the assignee for the bug.

http://bugzilla.slf4j.org/show_bug.cgi?id=173 --- Comment #12 from Thorsten <thorsten.Moeller@unibas.ch> 2010-08-25 14:52:05 --- The following behavior is now implemented (and tested) to shorten tag names exceeding the maximum length. The solution is inspired by Eclipse IDE which has a similar functionality. Each string on the left will be shortened to the string on the right: org.example.project.MyClass o*.e*.p*.MyClass org.example.project.subproject.MyClass o*.e*.p*.s*.MyClass org.example.MyQuiteLongNamedClassOfTooMuchCharacters o*.e*.MyQuiteLongNamed* o.e.project.subproject.MyClass o.e.p*.s*.MyClass MyQuiteLongNamedClassNotInAPackage MyQuiteLongNamedClassN* .................................. ......................* alskfdjhalskdfhalsdfkhalsdkfjhasld alskfdjhalskdfhalsdfkh* .alskjdfksdfj.asldkjfhksdfh.asdfm. a*.a*.asdfm .alskjdfksdfj.asldkjfhksdfh.asdfmasfdasdfasdfasdfasdfadf. a*.a*.asdfmasfdasdfasd* .MyQuiteLongNamedClassNotInAPackage MyQuiteLongNamedClassN* This behavior is going to become the final solution, which will be released soon, combined with the upgrade to version 1.6.1. -- Configure bugmail: http://bugzilla.slf4j.org/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- You are the assignee for the bug.

http://bugzilla.slf4j.org/show_bug.cgi?id=173 Thorsten <thorsten.Moeller@unibas.ch> changed: What |Removed |Added ---------------------------------------------------------------------------- Status|ASSIGNED |RESOLVED Resolution| |FIXED -- Configure bugmail: http://bugzilla.slf4j.org/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- You are the assignee for the bug.

http://bugzilla.slf4j.org/show_bug.cgi?id=173 idolon <idolon.dev@gmail.com> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |idolon.dev@gmail.com --- Comment #13 from idolon <idolon.dev@gmail.com> --- Just FYI. I've just checked all android.util.Log methods v(), d(), i(), w() and e() on Android 2.2 and 4.1 - neither of it throws an exception even with very long tag. (however Eclipse LogCat view doesn't correctly display messages if tag.length + time.length > 128 characters). The only place where tag is checked for 23 chars length - isLoggable() method. I've filled issue on Android bug tracker to correct this most likely obsolete behavior: https://code.google.com/p/android/issues/detail?id=59186 test code: String TAG_LEN_23 = "abcdefghijklmnopqrstuvw"; String TAG_LEN_26 = "abcdefghijklmnopqrstuvwxyz"; String TAG_LEN_80 = "01234567890123456789012345678901234567890123456789012345678901234567890123456789"; String TAG_LEN_100 = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"; Log.i(TAG_LEN_23, "blabla"); // no exception under both 2.2 and 4.1 Log.i(TAG_LEN_26, "blabla"); // no exception either Log.i(TAG_LEN_80, "blabla"); Log.v(TAG_LEN_80, "blabla"); Log.d(TAG_LEN_80, "blabla"); Log.w(TAG_LEN_80, "blabla"); Log.e(TAG_LEN_80, "blabla"); // still no exception but Eclipse LogCat view will display it incorrectly Log.i(TAG_LEN_100, "blabla"); -- You are receiving this mail because: You are the assignee for the bug.

http://bugzilla.slf4j.org/show_bug.cgi?id=173 --- Comment #14 from idolon <idolon.dev@gmail.com> --- Taking into account my comment above, maybe we should relax the tag length limitation from 23 to at least 80? -- You are receiving this mail because: You are the assignee for the bug.

http://bugzilla.slf4j.org/show_bug.cgi?id=173 --- Comment #15 from Thorsten <thorsten.Moeller@unibas.ch> --- (In reply to comment #13)
Just FYI. I've just checked all android.util.Log methods v(), d(), i(), w() and e() on Android 2.2 and 4.1 - neither of it throws an exception even with very long tag. (however Eclipse LogCat view doesn't correctly display messages if tag.length + time.length > 128 characters).
The only place where tag is checked for 23 chars length - isLoggable() method. Correct. AFAIR, this behavior exists already in Android 1.5.
I've filled issue on Android bug tracker to correct this most likely obsolete behavior: https://code.google.com/p/android/issues/detail?id=59186 Great! This should be the direction in which to put forward this issue.
(In reply to comment #14)
Taking into account my comment above, maybe we should relax the tag length limitation from 23 to at least 80? Don't agree because it makes things more difficult. How would "is...Enabled" methods be implemented then: delegate to the backing Android "isLoggable" logger method? No longer possible directly because they would throw IAE if tag length > 23. Extend the AndroidLogger such that it implements its own logic on this? Possible, but, first, it makes it more heavyweight, which, recalling the original design goal of having the most simple adapter between SLF4J and AndroidLogging, breaks this goal.
I would really love to see the limitation issue being solved at Android side rather than working around it. -- You are receiving this mail because: You are the assignee for the bug.

http://bugzilla.slf4j.org/show_bug.cgi?id=173 --- Comment #16 from idolon <idolon.dev@gmail.com> ---
(In reply to comment #14)
Taking into account my comment above, maybe we should relax the tag length limitation from 23 to at least 80? Don't agree because it makes things more difficult. How would "is...Enabled" methods be implemented then: delegate to the backing Android "isLoggable" logger method? No longer possible directly because they would throw IAE if tag length > 23. Extend the AndroidLogger such that it implements its own logic on this? Possible, but, first, it makes it more heavyweight, which, recalling the original design goal of having the most simple adapter between SLF4J and AndroidLogging, breaks this goal.
I would really love to see the limitation issue being solved at Android side rather than working around it.
At first I wished to write that the issue would *never* be solved on the existing devices, only in the upcoming Android versions and bla-bla-bla. But then I asked myself why for the hell that checks for 23 characters exists at all? And only in "Log.isLoggable" method. So I've dug a little bit deeper into the source code and reread the documentation carefully (yeah, I should have done this before posting my first comment here), and that's what I've realized: 1) "Log.isLoggable: checks to see whether or not a log for the specified tag is loggable at the specified level. The default level of any tag is set to INFO ... You can change the default level by setting a system property: setprop log.tag.<YOUR_LOG_TAG> <LEVEL>" 2) But system property name can't exceed 32 character including terminating '\0' http://androidxref.com/4.3_r2.1/xref/system/core/include/cutils/properties.h... 3) Taking into account p.1 and p.2 we can safely conclude that for ALL tag lengths > 23 "AndroidLogger.isTraceEnabled" and "isDebugEnabled" should return "false", and all others "is...Enabled" should return "true". Do you see what I mean? -- You are receiving this mail because: You are the assignee for the bug.
participants (2)
-
bugzilla-daemon@pixie.qos.ch
-
bugzilla-daemon@qos.ch