diff --git a/dynamic.c b/dynamic.c
index 9e77707288..4ab9ca70b6 100644
--- a/dynamic.c
+++ b/dynamic.c
@@ -17,6 +17,7 @@
 #include "general.h"
 #include "compat/strl.h"
 #include "compat/posix_string.h"
+#include "retroarch_logger.h"
 #include "file.h"
 #include <string.h>
 #include <ctype.h>
@@ -471,6 +472,36 @@ void dylib_close(dylib_t lib)
 }
 #endif
 
+static void rarch_log_libretro(enum retro_log_level level, const char *fmt, ...)
+{
+   va_list vp;
+   va_start(vp, fmt);
+
+   switch (level)
+   {
+      case RETRO_LOG_DEBUG:
+         RARCH_LOG_V("[libretro DEBUG] :: ", fmt, vp);
+         break;
+
+      case RETRO_LOG_INFO:
+         RARCH_LOG_OUTPUT_V("[libretro INFO] :: ", fmt, vp);
+         break;
+
+      case RETRO_LOG_WARN:
+         RARCH_WARN_V("[libretro WARN] :: ", fmt, vp);
+         break;
+
+      case RETRO_LOG_ERROR:
+         RARCH_ERR_V("[libretro ERROR] :: ", fmt, vp);
+         break;
+
+      default:
+         break;
+   }
+
+   va_end(vp);
+}
+
 bool rarch_environment_cb(unsigned cmd, void *data)
 {
    unsigned p, id;
@@ -795,6 +826,14 @@ bool rarch_environment_cb(unsigned cmd, void *data)
       }
 #endif
 
+      case RETRO_ENVIRONMENT_GET_LOG_INTERFACE:
+      {
+         RARCH_LOG("Environ GET_LOG_INTERFACE.\n");
+         struct retro_log_callback *cb = (struct retro_log_callback*)data;
+         cb->log = rarch_log_libretro;
+         break;
+      }
+
       // Private extensions for internal use, not part of libretro API.
       case RETRO_ENVIRONMENT_SET_LIBRETRO_PATH:
          RARCH_LOG("Environ (Private) SET_LIBRETRO_PATH.\n");
diff --git a/libretro.h b/libretro.h
index afbf10f434..5eaf99cf2f 100755
--- a/libretro.h
+++ b/libretro.h
@@ -539,6 +539,7 @@ enum retro_mod
                                            // The purpose of this interface is to allow
                                            // setting state related to sensors such as polling rate, enabling/disable it entirely, etc.
                                            // Reading sensor state is done via the normal input_state_callback API.
+                                           //
 #define RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE (26 | RETRO_ENVIRONMENT_EXPERIMENTAL)
                                            // struct retro_camera_callback * --
                                            // Gets an interface to a video camera driver.
@@ -556,6 +557,31 @@ enum retro_mod
                                            //
                                            // The camera is not started automatically. The retrieved start/stop functions must be used to explicitly
                                            // start and stop the camera driver.
+                                           //
+#define RETRO_ENVIRONMENT_GET_LOG_INTERFACE 27
+                                           // struct retro_log_callback * --
+                                           // Gets an interface for logging. This is useful for logging in a cross-platform way
+                                           // as certain platforms cannot use use stderr for logging. It also allows the frontend to
+                                           // show logging information in a more suitable way.
+                                           // If this interface is not used, libretro cores should log to stderr as desired.
+
+enum retro_log_level
+{
+   RETRO_LOG_DEBUG = 0,
+   RETRO_LOG_INFO,
+   RETRO_LOG_WARN,
+   RETRO_LOG_ERROR,
+
+   RETRO_LOG_DUMMY = INT_MAX
+};
+
+// Logging function. Takes log level argument as well.
+typedef void (*retro_log_printf_t)(enum retro_log_level level, const char *fmt, ...);
+
+struct retro_log_callback
+{
+   retro_log_printf_t log;
+};
 
 // FIXME: Document the sensor API and work out behavior.
 // It will be marked as experimental until then.
diff --git a/retroarch_logger.h b/retroarch_logger.h
index c8fa9ef7aa..bc6d30b220 100644
--- a/retroarch_logger.h
+++ b/retroarch_logger.h
@@ -17,6 +17,8 @@
 #ifndef __RARCH_LOGGER_H
 #define __RARCH_LOGGER_H
 
+#include <stdarg.h>
+
 #define RARCH_INTERNAL
 
 #if defined(ANDROID) && defined(HAVE_LOGGER)
@@ -38,6 +40,7 @@
 #elif defined(_XBOX1)
 #include "logger/xdk1_logger_override.h"
 #else
+
 #if defined(RARCH_DUMMY_LOG) || !defined(RARCH_INTERNAL)
 #define RARCH_LOG_VERBOSE (true)
 #else
@@ -45,13 +48,20 @@
 #endif
 
 #ifndef RARCH_LOG
+#undef RARCH_LOG_V
 #if defined(ANDROID) && defined(HAVE_LOGGER)
-#define  RARCH_LOG(...)  __android_log_print(ANDROID_LOG_INFO, "RetroArch: ", __VA_ARGS__)
+#define RARCH_LOG(...)  __android_log_print(ANDROID_LOG_INFO, "RetroArch: ", __VA_ARGS__)
+#define RARCH_LOG_V(tag, fmt, vp) __android_log_vprint(ANDROID_LOG_INFO, "RetroArch: " tag, fmt, vp)
 #elif defined(IS_SALAMANDER)
 #define RARCH_LOG(...) do { \
       fprintf(LOG_FILE, "RetroArch Salamander: " __VA_ARGS__); \
       fflush(LOG_FILE); \
    } while (0)
+#define RARCH_LOG_V(tag, fmt, vp) do { \
+      fprintf(LOG_FILE, "RetroArch Salamander: " tag); \
+      vfprintf(LOG_FILE, fmt, vp); \
+      fflush(LOG_FILE); \
+   } while(0)
 #else
 #define RARCH_LOG(...) do { \
       if (RARCH_LOG_VERBOSE) \
@@ -60,17 +70,22 @@
          fflush(LOG_FILE); \
       } \
    } while (0)
+#define RARCH_LOG_V(tag, fmt, vp) do { \
+      if (RARCH_LOG_VERBOSE) \
+      { \
+         fprintf(LOG_FILE, "RetroArch: " tag); \
+         vfprintf(LOG_FILE, fmt, vp); \
+         fflush(LOG_FILE); \
+      } \
+   } while (0)
 #endif
 #endif
 
 #ifndef RARCH_LOG_OUTPUT
-#if defined(ANDROID) && defined(HAVE_LOGGER)
-#define  RARCH_LOG_OUTPUT(...)  __android_log_print(ANDROID_LOG_INFO,"stderr: ",__VA_ARGS__)
-#elif defined(IS_SALAMANDER)
-#define RARCH_LOG_OUTPUT(...) do { \
-      fprintf(LOG_FILE, "stderr: " __VA_ARGS__); \
-      fflush(LOG_FILE); \
-   } while (0)
+#undef RARCH_LOG_OUTPUT_V
+#if (defined(ANDROID) && defined(HAVE_LOGGER)) || defined(IS_SALAMANDER)
+#define RARCH_LOG_OUTPUT(...) RARCH_LOG(__VA_ARGS__)
+#define RARCH_LOG_OUTPUT_V(tag, fmt, vp) RARCH_LOG_V(tag, fmt, vp)
 #else
 #define RARCH_LOG_OUTPUT(...) do { \
       if (RARCH_LOG_VERBOSE) \
@@ -79,73 +94,73 @@
          fflush(LOG_FILE); \
       } \
    } while (0)
+#define RARCH_LOG_OUTPUT_V(tag, fmt, vp) do { \
+      if (RARCH_LOG_VERBOSE) \
+      { \
+         fprintf(LOG_FILE, "RetroArch: " tag); \
+         vfprintf(LOG_FILE, fmt, vp); \
+         fflush(LOG_FILE); \
+      } \
+   } while (0)
 #endif
 #endif
 
 #ifndef RARCH_ERR
+#undef RARCH_ERR_V
 #if defined(ANDROID) && defined(HAVE_LOGGER)
-#define  RARCH_ERR(...)  __android_log_print(ANDROID_LOG_INFO, "RetroArch [ERROR] :: ", __VA_ARGS__)
+#define RARCH_ERR(...)  __android_log_print(ANDROID_LOG_INFO, "RetroArch [ERROR] :: ", __VA_ARGS__)
+#define RARCH_ERR_V(tag, fmt, vp) __android_log_vprint(ANDROID_LOG_INFO, "RetroArch [ERROR] :: " tag, fmt, vp)
 #elif defined(IS_SALAMANDER)
 #define RARCH_ERR(...) do { \
       fprintf(LOG_FILE, "RetroArch Salamander [ERROR] :: " __VA_ARGS__); \
       fflush(LOG_FILE); \
    } while (0)
+#define RARCH_ERR_V(tag, fmt, vp) do { \
+      fprintf(LOG_FILE, "RetroArch Salamander [ERROR] :: " tag); \
+      vfprintf(LOG_FILE, fmt, vp); \
+      fflush(LOG_FILE); \
+   } while (0)
 #else
 #define RARCH_ERR(...) do { \
       fprintf(LOG_FILE, "RetroArch [ERROR] :: " __VA_ARGS__); \
       fflush(LOG_FILE); \
    } while (0)
-#endif
-#endif
-
-#ifndef RARCH_ERR_OUTPUT
-#if defined(ANDROID) && defined(HAVE_LOGGER)
-#define  RARCH_ERR_OUTPUT(...)  __android_log_print(ANDROID_LOG_INFO, "stderr [ERROR] :: ", __VA_ARGS__)
-#elif defined(IS_SALAMANDER)
-#define RARCH_ERR_OUTPUT(...) do { \
-      fprintf(LOG_FILE, "stderr [ERROR] :: " __VA_ARGS__); \
-      fflush(LOG_FILE); \
-   } while (0)
-#else
-#define RARCH_ERR_OUTPUT(...) do { \
-      fprintf(LOG_FILE, "stderr [ERROR] :: " __VA_ARGS__); \
+#define RARCH_ERR_V(tag, fmt, vp) do { \
+      fprintf(LOG_FILE, "RetroArch [ERROR] :: " tag); \
+      vfprintf(LOG_FILE, fmt, vp); \
       fflush(LOG_FILE); \
    } while (0)
 #endif
 #endif
 
 #ifndef RARCH_WARN
+#undef RARCH_WARN_V
 #if defined(ANDROID) && defined(HAVE_LOGGER)
-#define  RARCH_WARN(...)  __android_log_print(ANDROID_LOG_INFO, "RetroArch [WARN] :: ", __VA_ARGS__)
+#define RARCH_WARN(...) __android_log_print(ANDROID_LOG_INFO, "RetroArch [WARN] :: ", __VA_ARGS__)
+#define RARCH_WARN_V(tag, fmt, vp) __android_log_print(ANDROID_LOG_INFO, "RetroArch [WARN] :: " tag, fmt, vp)
 #elif defined(IS_SALAMANDER)
 #define RARCH_WARN(...) do { \
       fprintf(LOG_FILE, "RetroArch Salamander [WARN] :: " __VA_ARGS__); \
       fflush(LOG_FILE); \
    } while (0)
+#define RARCH_WARN_V(tag, fmt, vp) do { \
+      fprintf(LOG_FILE, "RetroArch Salamander [WARN] :: " tag); \
+      vfprintf(LOG_FILE, fmt, vp); \
+      fflush(LOG_FILE); \
+   } while (0)
 #else
 #define RARCH_WARN(...) do { \
       fprintf(LOG_FILE, "RetroArch [WARN] :: " __VA_ARGS__); \
       fflush(LOG_FILE); \
    } while (0)
-#endif
-#endif
-
-#ifndef RARCH_WARN_OUTPUT
-#if defined(ANDROID) && defined(HAVE_LOGGER)
-#define  RARCH_WARN_OUTPUT(...)  __android_log_print(ANDROID_LOG_INFO, "stderr [WARN] :: ", __VA_ARGS__)
-#elif defined(IS_SALAMANDER)
-#define RARCH_WARN_OUTPUT(...) do { \
-      fprintf(LOG_FILE, "stderr [WARN] :: " __VA_ARGS__); \
-      fflush(LOG_FILE); \
-   } while (0)
-#else
-#define RARCH_WARN_OUTPUT(...) do { \
-      fprintf(LOG_FILE, "stderr [WARN] :: " __VA_ARGS__); \
+#define RARCH_WARN_V(tag, fmt, vp) do { \
+      fprintf(LOG_FILE, "RetroArch [WARN] :: " tag); \
+      vfprintf(LOG_FILE, fmt, vp); \
       fflush(LOG_FILE); \
    } while (0)
 #endif
 #endif
-#endif
 
 #endif
+#endif