I'm using logback for android, and I'm configuring it in code because I want the log directory to dynamically change depending on the phone (e.g. some phones have external storage and I want to write to that, but other phones don't so we have to redirect to internal storage).
Here is my config code:
File logFilesDir = getLogFilesDir(this);
LoggerContext lc = (LoggerContext)LoggerFactory.getILoggerFactory();
lc.reset();
RollingFileAppender<ILoggingEvent> fileAppender = null;
lc.putProperty("LOG_DIR", logFilesDir.getAbsolutePath());
PatternLayoutEncoder encoder = new PatternLayoutEncoder();
encoder.setContext(lc);
encoder.setPattern("%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n");
encoder.start();
File logFile = new File(logFilesDir, "MyApplication.log");
FixedWindowRollingPolicy rollingPolicy = new FixedWindowRollingPolicy();
rollingPolicy.setContext(lc);
rollingPolicy.setFileNamePattern("${LOG_DIR}/MyApplication.%i.log");
rollingPolicy.setMinIndex(1);
rollingPolicy.setMaxIndex(5);
SizeBasedTriggeringPolicy<ILoggingEvent> triggeringPolicy = new SizeBasedTriggeringPolicy<>();
triggeringPolicy.setContext(lc);
triggeringPolicy.setMaxFileSize("1KB"); // for testing; would otherwise be 5MB
fileAppender = new RollingFileAppender<>();
fileAppender.setContext(lc);
fileAppender.setFile(logFile.getAbsolutePath());
fileAppender.setEncoder(encoder);
fileAppender.setRollingPolicy(rollingPolicy);
fileAppender.setTriggeringPolicy(triggeringPolicy);
rollingPolicy.setParent(fileAppender);
fileAppender.start();
rollingPolicy.start();
triggeringPolicy.start();
// add the newly created appenders to the root logger;
// qualify Logger to disambiguate from org.slf4j.Logger
ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
root.addAppender(fileAppender);
root.info("----- Application onCreate -----");
StatusPrinter.print(lc);
The log writes to the correct folder and it's all working ok, except when my log file exceeds the max file size (in my testing case 1KB) it fails to roll over. Instead, the file just keeps growing.
StatusPrinter.print writes the following output, which looks like everything's ok
|-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [assets/logback.xml]
|-INFO in ch.qos.logback.core.rolling.RollingFileAppender[null] - Active log file name: /storage/emulated/0/MyApplication/logs/MyApplication.log
|-INFO in ch.qos.logback.core.rolling.RollingFileAppender[null] - File property is set to [/storage/emulated/0/MyApplication/logs/MyApplication.log]
|-INFO in ch.qos.logback.core.rolling.FixedWindowRollingPolicy#34b71b53 - No compression will be used
I've looked at as many other similar issues as I can find, and usually people seem to miss out the RollingFileAppender or don't have WRITE_EXTERNAL_STORAGE permission... It doesn't seem to me like I'm hitting any of those cases. Is something about my code (vs the XML people normally use) different?
Is there anything I can do to fix this or troubleshoot it further?
Thanks
I can't immediately tell what the problem is, but it would be helpful add an OnConsoleStatusListener to see what happens during the rollover:
LoggerContext lc = (LoggerContext)LoggerFactory.getILoggerFactory();
lc.reset();
OnConsoleStatusListener.addNewInstanceToContext(lc);
Rollover problems from RollingFileAppender are typically caused by a mix of absolute and relative paths in their configuration (Issue #117, Issue #110) or missing the WRITE_EXTERNAL_STORAGE permission (which is not the case for you). The debug output from OnConsoleStatusListener might shed some light. If not, I can try to debug it if you create a GitHub Issue, preferably with an Android Studio project that reproduces the problem.
Related
I'm studying the android kernel as a beginner. I can read the messages thrown from the macro ERROR() inside the function main() at system/core/init/init.c using dmesg command through adb. I observed that after calling the function open_devnull_stdio() inside main(), dmesg no longer displays the messages thrown by ERROR().
To find the reason, I started digging into the declaration of open_devnull_stdio() inside system/core/init/util.c and I found this line I can't understand
static const char *name = "/dev/__null__";
Actually there was no file named __null__ inside /dev/ in the device, but there was a file named null and I was able to grab it using adb pull and it was a 0 byte (empty) file.
So why is a file name wrapped with double underscore (__) ?
Here is the link for the util.c
There is no special purpose of using double underscore before the start, after the end or both in C. From the point of view of C the file name is just a string, the operating system is free to interpret in whatever way it chooses. From the point of view of Linux, the same applies. Underscores in file names are just characters. They are not treated differently from the letters b and t.
If I guessed right and I'm reading the same file as you (it might be a good idea to link to the source code you're reading) then it should be pretty obvious what the code does on the lines after the one you mentioned. The next lines are:
if (mknod(name, S_IFCHR | 0600, (1 << 8) | 3) == 0) {
fd = open(name, O_RDWR);
unlink(name);
Which creates the null device which is then opened and immediately deleted again.
I suspect this is done so that programs can run without access to the root filesystem and still be able to open the equivalent of /dev/null.
I don't know the answer but I have an idea:
The following page shows an "strace" output where /dev/__null__ is used:
https://gist.github.com/tetsu-koba/1522515
Under Linux device files have a 33-bit (?) number which identifies the device. (At least under old Linux versions) you could delete some file in /dev and you could restore it or even create it in another directory (!) when you know the 33-bit number! (So you can delete the device /dev/sda2 and create the device (not file!) /home/myuser/sda2 instead.)
The trace in the link above shows the following three lines:
mknod("/dev/__null__", S_IFCHR|0600, makedev(1, 3)) = 0
open("/dev/__null__", O_RDWR|O_LARGEFILE) = 3
unlink("/dev/__null__") = 0
These lines will create the device file /dev/__null__ (with the 33-bit number identifying /dev/null). Then it opens that file and then it removes the file again.
Maybe this is done because the tool shall be able to run both on Linux installations where the device file "/dev/null" is present (in this case the file should not be overwritten) and on installations where that file is missing (in this case a replacement file must be created using the known 33-bit number).
As other people have pointed out this just tells it's the "null device", not a regular file called "null". null is supposed to act like an information sink, not like a normal file where you dump your data to. Hope this helps.
How does one attach a specific app which is to be tested to Selendroid?
I've seen the example with the test app which is displayed virtually everywhere, but well, where do I have to place that apk under test?
I tried to use the id of the app like this:
SelendroidConfiguration config = new SelendroidConfiguration();
config.addSupportedApp("io.selendroid.testapp:0.17.0");
SelendroidLauncher selendroidServer = new SelendroidLauncher(config);
selendroidServer.launchSelendroid();
DesiredCapabilities caps = io.selendroid.common.SelendroidCapabilities.android();
SelendroidCapabilities cap = new SelendroidCapabilities("io.selendroid.testapp:0.17.0");
But I keep receiving errors: SessionNotCreatedException. What is causing this?
How do I attach a specific app to the Java project with the tests?
Seems like the issue is caused by not giving the correct path to your apk.
Here you should give the path to the apk, but you are giving it the package name of the app
config.addSupportedApp("io.selendroid.testapp:0.17.0");
The fix would be then
config.addSupportedApp("C:/Users/Madis/Documents/selendroid.apk");
I want to access a android device from python to download some photos.
libmtp works from the CLI.
Than pymtp. It's been around for a while but it's designed for python 2 and i'm using python 3. Meanwhile fixed several minor issues but i'm stuck at an error from function get_filelisting
specially this section:
ret = []
next = files
while next:
ret.append(next.contents)
if (next(next.contents) is None):
break
next = next(next.contents)
The error is related to the "next".
That section looks strange to me, i've been coding in python for a while but i'm new to ctypes. Tried a lot of variants, they all failed. The "next" could be confusing with python buildin function so i renamed it to nextpointer and came to this code:
ret = []
nextpointer = files
while nextpointer:
ret.append(nextpointer.contents)
nextpointer = nextpointer.contents.next
It seems to work but did it work by accident ? does it have any design flaws ? Could anyone with experience on python ctypes confirm this a solution ? Any suggestion welcome.
From python2.7 documentation
next(iterator[, default])
Retrieve the next item from the iterator by calling its next() method. If default is given, it is returned if the iterator is
exhausted, otherwise StopIteration is raised.
from python3 documentation
next(iterator[, default])
Retrieve the next item from the iterator by calling its __next__() method. If default is given, it is returned if the iterator is
exhausted, otherwise StopIteration is raised.
Notice that next() method was removed from python3 but the function still exists.
This is all I can say about the next function and .next()/__next__() methods.
I downloaded the pymtp module and get_filelisting() is slightly different from what you posted in your ported code, here it is:
ret = []
next = files
while next:
ret.append(next.contents)
if (next.contents.next == None):
break
next = next.contents.next
If none of this helped you (which probably didn't :D), the version of pymtp library that I am using is 0.0.6 download using pip.
I'm implementing schema validation using libxml2. The schema I'm validating against imports two other schemas with lines like:
<xs:import namespace="http://www.w3.org/XML/1998/namespace"
schemaLocation="http://www.somewebsite.com/xsd/xml.xsd"/>
All three schema files are located in the same directory on the device.
This works well when the device has internet access, but fails when it does not, as libxml2 still attempts to download the imported schemas from the schemaLocation even though I'm passing in XML_PARSE_NONET.
I tried getting libxml2 to load the files locally by editing the schemaLocation attribute to xml.xsd, ./xml.xsd, and file:///data/data/com.company.appname/files/xml.xsd, but all three resulted in the same libxml2 error:
domain: 16
code: 3069 (XML_SCHEMAP_INTERNAL)
message: Internal error: xmlSchemaParse, An internal error occurred.
I also tried removing the schemaLocation attribute entirely, on the off-chance that libxml2 might search for the imported schemas alongside the original schema, but that resulted in the following error when the schema parser hit a line that referenced the imported entities:
<xs:attribute ref="xml:lang" use="required"/>
domain: 16
code: 3004 (XML_SCHEMAP_SRC_RESOLVE)
message: attribute use (unknown), attribute 'ref': The QName value '{http://www.w3.org/XML/1998/namespace}lang' does not resolve to a(n) attribute declaration.
I also looked into manually merging the three schemas into a single file, but as they use different namespaces, this is not possible.
The standard solution for this seems to be the XML catalog, but I've read through libxml2's catalog documentation, and I can't figure out how (or even whether it's possible) to add mappings that will be used by my app when deployed to a device. I think I might need to implement an xmlExternalEntityLoader, but the documentation for that is quite slim.
How can I get libxml2 to import these schemas without network access? Obviously I'd ideally like a robust solution that works with the unedited schema, but I've be content with something quick-and-dirty that involves editing the schema, like my original attempts described above.
The errors described above are from an Android device (using JNI), but I'm having similar problems on iOS, where the solution will also need to work.
One way to do this is to intercept libxml2's call to open the imported URL with a custom xmlExternalEntityLoader.
The basic code for doing this is as follows:
#include <libxml/xmlIO.h>
#include <libxml/parserinternals.h>
xmlExternalEntityLoader defaultLoader = NULL;
xmlParserInputPtr
xmlMyExternalEntityLoader(const char *URL, const char *ID,
xmlParserCtxtPtr ctxt) {
xmlParserInputPtr ret;
const char *fileID = NULL;
/* lookup for the fileID
* The documentation suggests using the ID, but for me this was
* always NULL so I had to lookup by URL instead.
*/
ret = xmlNewInputFromFile(ctxt, fileID);
if (ret != NULL)
return(ret);
if (defaultLoader != NULL)
ret = defaultLoader(URL, ID, ctxt);
return(ret);
}
int main(..) {
...
/*
* Install our own entity loader
*/
defaultLoader = xmlGetExternalEntityLoader();
xmlSetExternalEntityLoader(xmlMyExternalEntityLoader);
...
}
(Slightly adjusted from the sample code in The entities loader section of libxml2's I/O Interfaces documentation.)
Is it a violation if the INI format to have a single linefeed (0x0A) that is not preceded by a carraige return (0x0D)?
Ini4j is puking on this in my Android app.
Please abstain from asking why I'm using INI in an Android app...
Since *.ini is a windows format, you can expect, that each newline must be \r\n.
At least in the sources, only the Registry class definitivly relies on \r\n. In all other cases it seems, as if the system property line.separator is used.
It's still arguable is a cross-plattform library should rely on it...
The problem can be resolved setting setEmptyOption(true) e.g.
Config c = new Config();
c.setEmptyOption(true);
Ini i = new Ini();
i.setConfig(c);