Skip to main content
Version: 1.1.8.2

Logging

When something goes wrong (and it will), logs are your best friend. The SDK uses SLF4J with Logback-Android — industry standards that give you full control over what gets logged and where.


Why Use Logging?​

Logging is essential for:

  • Debugging — Track down issues during development
  • Monitoring — Understand application behavior in production
  • Troubleshooting — Diagnose problems reported by users
  • Auditing — Keep records of device operations

Quick Setup​

1. Add Dependencies​

In your app/build.gradle:

dependencies {
// SLF4J API
implementation 'org.slf4j:slf4j-api:2.0.17'

// Logback-Android implementation
implementation 'com.github.tony19:logback-android:3.0.0'

// ... your other dependencies
}

2. Create the Config File​

Create app/src/main/assets/logback.xml:

<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://tony19.github.io/logback-android/xml"
xsi:schemaLocation="https://tony19.github.io/logback-android/xml https://cdn.jsdelivr.net/gh/tony19/logback-android/logback.xsd">

<appender name="logcat" class="ch.qos.logback.classic.android.LogcatAppender">
<tagEncoder>
<pattern>%logger{12}</pattern>
</tagEncoder>
<encoder>
<pattern>[%-20thread] %msg</pattern>
</encoder>
</appender>

<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOGS_DIR}/app.log</file>

<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOGS_DIR}/app.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>1MB</maxFileSize>
<maxHistory>100</maxHistory>
</rollingPolicy>

<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>

<!-- Set Log Level of specific package -->
<logger name="com.example.sdk" level="INFO" />

<root level="DEBUG">
<appender-ref ref="logcat" />
<appender-ref ref="FILE" />
</root>
</configuration>

3. Initialize the Log Directory​

In your Application class:

public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();

// Set log directory BEFORE any logging happens
System.setProperty("LOGS_DIR", getFilesDir().getAbsolutePath() + "/logs");
}
}

Register it in AndroidManifest.xml:

<application
android:name=".MyApplication"
... >

Done. Logging is ready.


Using Loggers​

Create a Logger​

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class PrintManager {
private final Logger logger = LoggerFactory.getLogger(PrintManager.class);

// Now use logger.debug(), logger.info(), etc.
}

Log Levels​

LevelWhen to UseExample
debugDetailed diagnostic infoVariable values, method calls
infoNormal operationsSuccessful connections, state changes
warnSomething unusualDeprecated API usage, recoverable errors
errorSomething failedFailed operations, caught exceptions

Example Usage​

public class DeviceOperations {
private final Logger logger = LoggerFactory.getLogger(DeviceOperations.class);

public void connectToDevice(DeviceConnection device) {
logger.debug("Attempting connection to: {}", device.getName());

deviceAdapter.connect()
.thenAccept(unused -> {
logger.info("Successfully connected to {}", device.getName());
})
.exceptionally(error -> {
logger.error("Connection failed for device: {}", device.getName(), error);
return null;
});
}

public void printLabel(String template, String data, int copies) {
logger.debug("Print request: template={}, copies={}", template, copies);

if (copies > 100) {
logger.warn("Large print job requested: {} copies", copies);
}

printerAdapter.print(template, data, copies)
.thenAccept(unused -> logger.info("Print job completed: {} copies", copies))
.exceptionally(error -> {
logger.error("Print failed: template={}", template, error);
return null;
});
}
}

Best Practices​

1. Use Parameterized Logging​

// ✅ Good — parameters only evaluated if level is enabled
logger.debug("Printing {} copies of {}", copies, templateName);

// ❌ Avoid — string concatenation always happens
logger.debug("Printing " + copies + " copies of " + templateName);

2. Log Exceptions Properly​

Pass the exception as the last parameter for full stack traces:

// ✅ Good — full stack trace in logs
logger.error("Operation failed for device {}", deviceName, exception);

// ❌ Avoid — loses stack trace
logger.error("Operation failed: " + exception.getMessage());

3. Include Context​

// ✅ Good — includes context
logger.error("Failed to print label '{}' on printer '{}'",
labelName, printerName, exception);

// ❌ Avoid — missing context
logger.error("Print failed", exception);

4. Don't Log Sensitive Data​

// ❌ Avoid — don't log passwords, tokens, personal data
logger.debug("Login with username: {} and password: {}", username, password);

// ✅ Good — log safe information only
logger.debug("Login attempt for user: {}", username);

5. Use Appropriate Levels​

// ✅ Good — appropriate levels
logger.debug("Processing item {} of {}", current, total);
logger.info("Connection established");
logger.warn("Retrying connection, attempt {}", attempt);
logger.error("Failed to connect", exception);

// ❌ Avoid — everything as ERROR
logger.error("Processing item"); // Should be DEBUG

Configuration Options​

Log Levels​

Control verbosity in logback.xml:

<!-- See everything from the SDK -->
<logger name="com.averydennison.addevicemanager" level="DEBUG" />

<!-- Only errors from noisy libraries -->
<logger name="some.chatty.library" level="ERROR" />

<!-- Default level for everything else -->
<root level="INFO">
<appender-ref ref="LOGCAT" />
</root>

Level hierarchy: DEBUG < INFO < WARN < ERROR

Setting level to INFO means you see INFO, WARN, and ERROR — but not DEBUG.

File Rotation​

Control how logs are stored:

<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- Daily rotation with index for size overflow -->
<fileNamePattern>${LOGS_DIR}/app.%d{yyyy-MM-dd}.%i.log</fileNamePattern>

<!-- Split file when it hits 1MB -->
<maxFileSize>1MB</maxFileSize>

<!-- Keep 7 days of logs -->
<maxHistory>7</maxHistory>

<!-- Never use more than 10MB total -->
<totalSizeCap>10MB</totalSizeCap>
</rollingPolicy>

Log Format​

Customize what each line looks like:

<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>

Pattern elements:

  • %d{...} — Date/time format
  • %thread — Thread name
  • %-5level — Log level (padded to 5 characters)
  • %logger{36} — Logger name (truncated to 36 characters)
  • %msg — Log message
  • %n — Line separator

Accessing Log Files​

Log files are stored in the app's private storage:

File logsDir = new File(getFilesDir(), "logs");
File[] logFiles = logsDir.listFiles();

if (logFiles != null) {
for (File logFile : logFiles) {
logger.info("Log file: {}, size: {} bytes",
logFile.getName(), logFile.length());
}
}

Sharing Log Files​

To share logs with support teams:

public void shareLogs() {
File logsDir = new File(getFilesDir(), "logs");
File latestLog = new File(logsDir, "app.log");

if (latestLog.exists()) {
Uri logUri = FileProvider.getUriForFile(
this,
"com.example.myapp.fileprovider",
latestLog
);

Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_STREAM, logUri);
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(Intent.createChooser(shareIntent, "Share logs"));
}
}

Troubleshooting​

Logs Not Appearing​

  1. Check log level — Ensure your logger level allows the message:

    <root level="DEBUG">  <!-- Must be DEBUG or lower to see debug messages -->
  2. Verify logback.xml — Ensure file is in src/main/assets/

  3. Check Application class — Verify LOGS_DIR is set before any logging

Log Files Not Created​

  1. Check directory — Verify the directory path exists and is writable:

    File logsDir = new File(getFilesDir(), "logs");
    if (!logsDir.exists()) {
    boolean created = logsDir.mkdirs();
    logger.info("Logs directory created: {}", created);
    }
  2. Verify property — Ensure LOGS_DIR system property is set in Application.onCreate()

Performance Issues​

If logging impacts performance:

  1. Reduce log level in production (INFO or WARN)
  2. Limit file size and history in logback.xml
  3. Use async appender for file logging:
    <appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender">
    <appender-ref ref="FILE" />
    </appender>

Next Steps​

GuideWhat You'll Learn
Getting StartedSDK setup and initialization
CallbacksMonitor SDK events
Error HandlingHandle failures gracefully
TelemetryDevice analytics and usage data

For more information about Logback-Android, visit: https://github.com/tony19/logback-android