Index: applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/FeatureAdapter.java
===================================================================
--- applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/FeatureAdapter.java	(revision 35018)
+++ applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/FeatureAdapter.java	(revision 35019)
@@ -12,4 +12,5 @@
 import java.util.Objects;
 import java.util.TreeMap;
+import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -109,4 +110,8 @@
     public static Logger getLogger(String name) {
         return loggingAdapter.getLogger(name);
+    }
+
+    public static Logger getLogger(Class<?> klass) {
+        return loggingAdapter.getLogger(klass.getSimpleName());
     }
 
@@ -155,5 +160,5 @@
                 }
             } else {
-                System.err.println(tr("Opening link not supported on current platform (''{0}'')", url));
+                getLogger(FeatureAdapter.class).log(Level.SEVERE, tr("Opening link not supported on current platform (''{0}'')", url));
             }
         }
Index: applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/OsmTileLoader.java
===================================================================
--- applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/OsmTileLoader.java	(revision 35018)
+++ applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/OsmTileLoader.java	(revision 35019)
@@ -15,4 +15,5 @@
 import java.util.concurrent.ThreadPoolExecutor;
 import java.util.logging.Level;
+import java.util.logging.Logger;
 
 import org.openstreetmap.gui.jmapviewer.interfaces.TileJob;
@@ -26,4 +27,7 @@
  */
 public class OsmTileLoader implements TileLoader {
+
+    private static final Logger LOG = FeatureAdapter.getLogger(OsmTileLoader.class);
+
     /** Setting key for number of threads */
     public static final String THREADS_SETTING = "jmapviewer.osm-tile-loader.threads";
@@ -34,7 +38,8 @@
             nThreads = FeatureAdapter.getIntSetting(THREADS_SETTING, DEFAULT_THREADS_NUMBER);
         } catch (Exception e) {
-            FeatureAdapter.getLogger(OsmTileLoader.class.getName()).log(Level.SEVERE, e.getMessage(), e);
-        }
-    }
+            LOG.log(Level.SEVERE, e.getMessage(), e);
+        }
+    }
+
     private static final ThreadPoolExecutor jobDispatcher = (ThreadPoolExecutor) Executors.newFixedThreadPool(nThreads);
 
@@ -81,8 +86,8 @@
                 if (input == null) {
                     try {
-                        System.err.println("Failed loading " + tile.getUrl() +": "
+                        LOG.log(Level.SEVERE, "Failed loading " + tile.getUrl() +": "
                                 +e.getClass() + ": " + e.getMessage());
                     } catch (IOException ioe) {
-                        ioe.printStackTrace();
+                        LOG.log(Level.SEVERE, ioe.getMessage(), ioe);
                     }
                 }
@@ -115,4 +120,8 @@
     protected TileLoaderListener listener;
 
+    /**
+     * Constructs a new {@code OsmTileLoader}.
+     * @param listener tile loader listener
+     */
     public OsmTileLoader(TileLoaderListener listener) {
         this(listener, null);
Index: applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/tilesources/BingAerialTileSource.java
===================================================================
--- applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/tilesources/BingAerialTileSource.java	(revision 35018)
+++ applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/tilesources/BingAerialTileSource.java	(revision 35019)
@@ -15,4 +15,6 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 import java.util.regex.Pattern;
 
@@ -43,4 +45,6 @@
 public class BingAerialTileSource extends TMSTileSource {
 
+    private static final Logger LOG = FeatureAdapter.getLogger(BingAerialTileSource.class);
+
     /** Setting key for Bing metadata API URL. Must contain {@link #API_KEY_PLACEHOLDER} */
     public static final String METADATA_API_SETTING = "jmapviewer.bing.metadata-api-url";
@@ -55,4 +59,5 @@
     /** Original Bing API key created by Potlatch2 developers in 2010 */
     private static final String API_KEY = "Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU";
+    
     private static volatile Future<List<Attribution>> attributions; // volatile is required for getAttribution(), see below.
     private static String imageUrlTemplate;
@@ -171,9 +176,6 @@
 
             return attributionsList;
-        } catch (SAXException e) {
-            System.err.println("Could not parse Bing aerials attribution metadata.");
-            e.printStackTrace();
-        } catch (ParserConfigurationException | XPathExpressionException | NumberFormatException e) {
-            e.printStackTrace();
+        } catch (SAXException | ParserConfigurationException | XPathExpressionException | NumberFormatException e) {
+            LOG.log(Level.SEVERE, "Could not parse Bing aerials attribution metadata.", e);
         }
         return null;
@@ -220,5 +222,5 @@
             }
         } catch (IOException e) {
-            System.err.println("Error while retrieving Bing logo: "+e.getMessage());
+            LOG.log(Level.SEVERE, "Error while retrieving Bing logo: "+e.getMessage());
         }
         return null;
@@ -253,5 +255,5 @@
                         return r;
                     } catch (IOException ex) {
-                        System.err.println("Could not connect to Bing API. Will retry in " + waitTimeSec + " seconds.");
+                        LOG.log(Level.SEVERE, "Could not connect to Bing API. Will retry in " + waitTimeSec + " seconds.");
                         Thread.sleep(TimeUnit.SECONDS.toMillis(waitTimeSec));
                         waitTimeSec *= 2;
@@ -276,9 +278,9 @@
             return attributions.get(0, TimeUnit.MILLISECONDS);
         } catch (TimeoutException ex) {
-            System.err.println("Bing: attribution data is not yet loaded.");
+            LOG.log(Level.WARNING, "Bing: attribution data is not yet loaded.");
         } catch (ExecutionException ex) {
             throw new RuntimeException(ex.getCause());
         } catch (InterruptedException ign) {
-            System.err.println("InterruptedException: " + ign.getMessage());
+            LOG.log(Level.SEVERE, "InterruptedException: " + ign.getMessage());
         }
         return null;
