diff --git a/glib/gmessages.c b/glib/gmessages.c
index f3e343b..c01092a 100644
--- a/glib/gmessages.c
+++ b/glib/gmessages.c
@@ -1947,6 +1947,59 @@ g_log_structured_array (GLogLevelFlags   log_level,
     _g_log_abort (!(log_level & G_LOG_FLAG_RECURSION));
 }
 
+/* Semi-private helper function to implement the g_message() (etc.) macros
+ * with support for G_GNUC_PRINTF so that @message_format can be checked
+ * with -Wformat. */
+void
+g_log_structured_standard (const gchar    *log_domain,
+                           GLogLevelFlags  log_level,
+                           const gchar    *file,
+                           const gchar    *line,
+                           const gchar    *func,
+                           const gchar    *message_format,
+                           ...)
+{
+  GLogField fields[] =
+    {
+      { "PRIORITY", log_level_to_priority (log_level), -1 },
+      { "CODE_FILE", file, -1 },
+      { "CODE_LINE", line, -1 },
+      { "CODE_FUNC", func, -1 },
+      /* Filled in later: */
+      { "MESSAGE", NULL, -1 },
+      /* If @log_domain is %NULL, we will not pass this field: */
+      { "GLIB_DOMAIN", log_domain, -1 },
+    };
+  gsize n_fields;
+  gchar *message_allocated = NULL;
+  gchar buffer[1025];
+  va_list args;
+
+  va_start (args, message_format);
+
+  if (log_level & G_LOG_FLAG_RECURSION)
+    {
+      /* we use a stack buffer of fixed size, since we're likely
+       * in an out-of-memory situation
+       */
+      gsize size G_GNUC_UNUSED;
+
+      size = _g_vsnprintf (buffer, sizeof (buffer), message_format, args);
+      fields[4].value = buffer;
+    }
+  else
+    {
+      fields[4].value = message_allocated = g_strdup_vprintf (message_format, args);
+    }
+
+  va_end (args);
+
+  n_fields = G_N_ELEMENTS (fields) - ((log_domain == NULL) ? 1 : 0);
+  g_log_structured_array (log_level, fields, n_fields);
+
+  g_free (message_allocated);
+}
+
 /**
  * g_log_set_writer_func:
  * @func: log writer function, which must not be %NULL
diff --git a/glib/gmessages.h b/glib/gmessages.h
index ee0dca8..d3025ab 100644
--- a/glib/gmessages.h
+++ b/glib/gmessages.h
@@ -282,6 +282,15 @@ void g_assert_warning         (const char *log_domain,
 		               const char *pretty_function,
 		               const char *expression) G_GNUC_NORETURN;
 
+_GLIB_EXTERN
+void g_log_structured_standard (const gchar    *log_domain,
+                                GLogLevelFlags  log_level,
+                                const gchar    *file,
+                                const gchar    *line,
+                                const gchar    *func,
+                                const gchar    *message_format,
+                                ...) G_GNUC_PRINTF (6, 7);
+
 
 #ifndef G_LOG_DOMAIN
 #define G_LOG_DOMAIN    ((gchar*) 0)
@@ -290,38 +299,26 @@ void g_assert_warning         (const char *log_domain,
 #if defined(G_HAVE_ISO_VARARGS) && !G_ANALYZER_ANALYZING
 #ifdef G_LOG_USE_STRUCTURED
 #define g_error(...)  G_STMT_START {                                            \
-                        g_log_structured (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR,      \
-                                          "CODE_FILE", __FILE__,                \
-                                          "CODE_LINE", G_STRINGIFY (__LINE__),  \
-                                          "CODE_FUNC", G_STRFUNC,                \
-                                          "MESSAGE", __VA_ARGS__);              \
+                        g_log_structured_standard (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, \
+                                                   __FILE__, G_STRINGIFY (__LINE__), \
+                                                   G_STRFUNC, __VA_ARGS__); \
                         for (;;) ;                                              \
                       } G_STMT_END
-#define g_message(...)  g_log_structured (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE,    \
-                                          "CODE_FILE", __FILE__,                \
-                                          "CODE_LINE", G_STRINGIFY (__LINE__),  \
-                                          "CODE_FUNC", G_STRFUNC,                \
-                                          "MESSAGE", __VA_ARGS__)
-#define g_critical(...) g_log_structured (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,   \
-                                          "CODE_FILE", __FILE__,                \
-                                          "CODE_LINE", G_STRINGIFY (__LINE__),  \
-                                          "CODE_FUNC", G_STRFUNC,                \
-                                          "MESSAGE", __VA_ARGS__)
-#define g_warning(...)  g_log_structured (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,    \
-                                          "CODE_FILE", __FILE__,                \
-                                          "CODE_LINE", G_STRINGIFY (__LINE__),  \
-                                          "CODE_FUNC", G_STRFUNC,                \
-                                          "MESSAGE", __VA_ARGS__)
-#define g_info(...)     g_log_structured (G_LOG_DOMAIN, G_LOG_LEVEL_INFO,       \
-                                          "CODE_FILE", __FILE__,                \
-                                          "CODE_LINE", G_STRINGIFY (__LINE__),  \
-                                          "CODE_FUNC", G_STRFUNC,                \
-                                          "MESSAGE", __VA_ARGS__)
-#define g_debug(...)    g_log_structured (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,      \
-                                          "CODE_FILE", __FILE__,                \
-                                          "CODE_LINE", G_STRINGIFY (__LINE__),  \
-                                          "CODE_FUNC", G_STRFUNC,                \
-                                          "MESSAGE", __VA_ARGS__)
+#define g_message(...)  g_log_structured_standard (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, \
+                                                   __FILE__, G_STRINGIFY (__LINE__), \
+                                                   G_STRFUNC, __VA_ARGS__)
+#define g_critical(...) g_log_structured_standard (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, \
+                                                   __FILE__, G_STRINGIFY (__LINE__), \
+                                                   G_STRFUNC, __VA_ARGS__)
+#define g_warning(...)  g_log_structured_standard (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, \
+                                                   __FILE__, G_STRINGIFY (__LINE__), \
+                                                   G_STRFUNC, __VA_ARGS__)
+#define g_info(...)     g_log_structured_standard (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, \
+                                                   __FILE__, G_STRINGIFY (__LINE__), \
+                                                   G_STRFUNC, __VA_ARGS__)
+#define g_debug(...)    g_log_structured_standard (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, \
+                                                   __FILE__, G_STRINGIFY (__LINE__), \
+                                                   G_STRFUNC, __VA_ARGS__)
 #else
 /* for(;;) ; so that GCC knows that control doesn't go past g_error().
  * Put space before ending semicolon to avoid C++ build warnings.
@@ -351,38 +348,26 @@ void g_assert_warning         (const char *log_domain,
 #elif defined(G_HAVE_GNUC_VARARGS)  && !G_ANALYZER_ANALYZING
 #ifdef G_LOG_USE_STRUCTURED
 #define g_error(format...)   G_STMT_START {                                          \
-                               g_log_structured (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR,    \
-                                                "CODE_FILE", __FILE__,               \
-                                                "CODE_LINE", G_STRINGIFY (__LINE__), \
-                                                "CODE_FUNC", G_STRFUNC,               \
-                                                "MESSAGE", format);                  \
+                               g_log_structured_standard (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, \
+                                                          __FILE__, G_STRINGIFY (__LINE__), \
+                                                          G_STRFUNC, format); \
                                for (;;) ;                                            \
                              } G_STMT_END
-#define g_message(format...)  g_log_structured (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE,   \
-                                               "CODE_FILE", __FILE__,                \
-                                               "CODE_LINE", G_STRINGIFY (__LINE__),  \
-                                               "CODE_FUNC", G_STRFUNC,                \
-                                               "MESSAGE", format)
-#define g_critical(format...) g_log_structured (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,  \
-                                                "CODE_FILE", __FILE__,               \
-                                                "CODE_LINE", G_STRINGIFY (__LINE__), \
-                                                "CODE_FUNC", G_STRFUNC,               \
-                                                "MESSAGE", format)
-#define g_warning(format...)  g_log_structured (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,   \
-                                                "CODE_FILE", __FILE__,               \
-                                                "CODE_LINE", G_STRINGIFY (__LINE__), \
-                                                "CODE_FUNC", G_STRFUNC,               \
-                                                "MESSAGE", format)
-#define g_info(format...)     g_log_structured (G_LOG_DOMAIN, G_LOG_LEVEL_INFO,      \
-                                                "CODE_FILE", __FILE__,               \
-                                                "CODE_LINE", G_STRINGIFY (__LINE__), \
-                                                "CODE_FUNC", G_STRFUNC,               \
-                                                "MESSAGE", format)
-#define g_debug(format...)    g_log_structured (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,     \
-                                                "CODE_FILE", __FILE__,               \
-                                                "CODE_LINE", G_STRINGIFY (__LINE__), \
-                                                "CODE_FUNC", G_STRFUNC,               \
-                                                "MESSAGE", format)
+#define g_message(format...)  g_log_structured_standard (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, \
+                                                         __FILE__, G_STRINGIFY (__LINE__), \
+                                                         G_STRFUNC, format)
+#define g_critical(format...) g_log_structured_standard (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, \
+                                                         __FILE__, G_STRINGIFY (__LINE__), \
+                                                         G_STRFUNC, format)
+#define g_warning(format...)  g_log_structured_standard (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, \
+                                                         __FILE__, G_STRINGIFY (__LINE__), \
+                                                         G_STRFUNC, format)
+#define g_info(format...)     g_log_structured_standard (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, \
+                                                         __FILE__, G_STRINGIFY (__LINE__), \
+                                                         G_STRFUNC, format)
+#define g_debug(format...)    g_log_structured_standard (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, \
+                                                         __FILE__, G_STRINGIFY (__LINE__), \
+                                                         G_STRFUNC, format)
 #else
 #define g_error(format...)    G_STMT_START {                 \
                                 g_log (G_LOG_DOMAIN,         \
