3

I'm trying to set up my app so I can write logs using logback-android, and then send them to Google Docs using ACRA. I think this is possible but the one issue I have, is where to write the logs.

Both libraries need a hard-coded filename, so I can't use getStorageDirectory(). So, my first question is, where do the logs get written if you don't specify a full path? Do I have to specify a full path and hardcode it to /data/data/com.example/...?

Here's my configuration:

<!-- Logback configuration. -->
<logback>
<configuration>
    <appender
        name="FILE"
        class="ch.qos.logback.core.FileAppender" >
        <file>applog.log</file>
        <encoder>
            <pattern>[%method] %msg%n</pattern>
        </encoder>
    </appender>
    <appender
        name="LOGCAT"
        class="ch.qos.logback.classic.android.LogcatAppender" >
        <tagEncoder>
            <pattern>%logger{0}</pattern>
        </tagEncoder>

        <encoder>
            <pattern>[%method] %msg%n</pattern>
        </encoder>
    </appender>

    <root level="debug" >
        <appender-ref ref="FILE" />
        <appender-ref ref="LOGCAT" />
    </root>
</configuration>
</logback>

And for acra:

@ReportsCrashes(formKey = "dDB4dVRlTjVWa05T..........................",
                applicationLogFile = "applog.log",
                applicationLogFileLines = 150)

But this gives errors like the following, so clearly I do need an absolute path. What should I use?

java.io.FileNotFoundException: /applog.log: open failed: EROFS (Read-only file system)

Final, slightly unrelated question, I want to be able to print the object address, something like [%object :: %method] which would show [MyActivity@33c0d9d :: onCreate] or something similar. Is there any way to do that?

Timmmm
  • 88,195
  • 71
  • 364
  • 509

2 Answers2

0

This is not a solution but an alternative.

If you have your own logging layer, you could just store the last 50/100/500 log messages in a circular buffer, and provide it to ACRA, when the crash occurs.

Circular buffer impl example:

public static final class LogRingBuffer {
    public static final int CAPACITY = 150;
    private String[] buffer = new String[CAPACITY];
    private int position = 0;
    private boolean full = false;
    public synchronized void append(String message) {cost of sync
        buffer[position] = message;
        position = (position+1)%CAPACITY;
        if (position==0) {
            full = true;
        }
    }

    public synchronized int size() {
        return full?CAPACITY:position;
    }

    public synchronized String get(int i) {
        return buffer[(position - i - 1 + CAPACITY) % CAPACITY];
    }
}

And then you have to provide log content as custom data fields:

int bcSize = Log.logBuffer.size();
for(int i=0; i<bcSize; ++i)
    reporter.addCustomData(String.format("LOG%03d", i), Log.logBuffer.get(i));

This latter one should be implemented in your own exception handler, that should surround ACRAs exception handler...

I admit, this is not stupid simple, but could save you some DISK I/O, and usage of logback-android...

Vajk Hermecz
  • 5,413
  • 2
  • 34
  • 25
0

There is another workaround.

Take a look on ACRA sources, file LogFileCollector.java. It opens application log file in a follow way:

if (fileName.contains("/")) {
    reader = new BufferedReader(new InputStreamReader(new FileInputStream(fileName)), 1024);
} else {
    reader = new BufferedReader(new InputStreamReader(context.openFileInput(fileName)), 1024);
}

It's possible to use context.openFileOutput for saving log messages and specify log-file name without path in ACRA configuration. I.e. log file class can be declared in follow way:

public class LogOnDisk {
    public static final String LOG_FILE_NAME = "custom_log";
    private final java.io.FileOutputStream _FS;
    private final java.io.PrintStream _PS;
    public LogOnDisk(Context context) throws IOException {
        _FS = context.openFileOutput(LOG_FILE_NAME, Context.MODE_PRIVATE);
        _PS = new PrintStream(_FS);
    }

    public synchronized void toLog(String message) {
        try {           
            _PS.print(message + "\n");
            _PS.flush();
        } catch (Exception ex) {
            //nothing to do
        }
    }       
}

ACRA configuration:

@ReportsCrashes(applicationLogFile = LogOnDisk.LOG_FILE_NAME)
public final class Kernel extends Application {
dvpublic
  • 657
  • 8
  • 8