Differences

This shows you the differences between two versions of the page.

Link to this comparison view

osgi_console_logger [2021/04/05 11:23] (current)
Line 1: Line 1:
 +====== OSGi Console Logger ======
 +Logging in OSGi can be very tedious. OSGi provided a very robust framework for logging but it misses one point:
  
 +<note important>The application developer does not want to implement his own logger. He wants to just use a logging implementation!</note>
 +  
 +And this is where OSGi misses the point with its very sophisticated framework. There is a framework but there is no implementation of the last link in the chain: //the output of the log//.
 +
 +Logging should be dead simple. But in OSGi it just isn't that simple. There is the LogService, the LogReader and the LogListener ... and the whole time I just think //"Hey, I just want to output some messages!"//
 +
 +Both popular OSGi frameworks (Eclipse Equinox and Apache Felix) have implementation for LogService and LogReader but the LogListener is not implemented for the end-user (the application developer).
 +
 +So here is a trivial implementation of a LogListener , using System.out:
 +
 +<sxh java>
 +import java.text.DateFormat;
 +import java.text.SimpleDateFormat;
 +import java.util.Date;
 +
 +import org.osgi.service.log.LogEntry;
 +import org.osgi.service.log.LogListener;
 +import org.osgi.service.log.LogReaderService;
 +import org.osgi.service.log.LogService;
 +
 +public class ConsoleLogListener implements LogListener {
 +
 + private static final String LOG_LEVEL_INFO = "INFO ";
 + private static final String LOG_LEVEL_WARN = "WARN ";
 + private static final String LOG_LEVEL_ERROR = "ERROR";
 + private static final String LOG_LEVEL_DEBUG = "DEBUG";
 +
 + private static final String[] LOG_LEVELS = { 
 + LOG_LEVEL_ERROR, LOG_LEVEL_WARN, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG 
 + };
 +
 + private DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 +
 + private int logLevel = LogService.LOG_INFO;
 +
 + public void bindLogReader(LogReaderService logReader) {
 + logReader.addLogListener(this);
 + }
 +
 + public void unbindLogReader(LogReaderService logReader) {
 + logReader.removeLogListener(this);
 + }
 +
 + @Override
 + public void logged(LogEntry entry) {
 + if (!isLoggable(entry)) {
 + return;
 + }
 +
 + String message = formatLogTime(entry.getTime()) + " " + formatLogLevel(entry.getLevel())
 + + " - " + entry.getBundle().getSymbolicName() + " - " + entry.getMessage();
 +
 + if (entry.getServiceReference() != null) {
 + message = message + " - [ " + entry.getServiceReference().getClass().getName() + " ("
 + + entry.getServiceReference().getProperty("service.id") + ") ]";
 + }
 +
 + System.out.println(message);
 + }
 +
 + private String formatLogTime(long time) {
 + return dateFormat.format(new Date(time));
 + }
 +
 + private String formatLogLevel(int logLevel) {
 + return LOG_LEVELS[--logLevel];
 + }
 +
 + private boolean isLoggable(LogEntry entry) {
 + boolean loggable = false;
 +
 + if (logLevel <= entry.getLevel()) {
 + loggable = true;
 + }
 +
 + return loggable;
 + }
 +
 +}
 +</sxh>
 +
 +<note>The message building method is totally unoptimized and is solely for demonstration purposes.</note>
 +
 +But that isn't doing the trick yet as it is nowhere registered in the logging framework. The easiest way to register it is to make a declarative component of it and bind the LogReader implementations to it, file //OSGI-INF/service-log.xml//.
 +
 +<sxh xml>
 +<?xml version="1.0" encoding="UTF-8"?>
 +<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="miworkplace.log.console">
 +   <implementation class="miworkplace.log.ConsoleLogListener"/>
 +   <reference bind="bindLogReader" cardinality="0..n" interface="org.osgi.service.log.LogReaderService" name="LogReaderService" policy="dynamic" unbind="unbindLogReader"/>
 +</scr:component>
 +</sxh>
 +
 +<note tip>Don't forget to add the component to the MANIFEST.MF: <code>Service-Component: OSGI-INF/service-log.xml</code></note>
 +
 +{{tag>devel java osgi}}