[glib] Add g_log_variant(): structured log that accepts a GVariant



commit e7bdd5d189ed788e667c54824e314df496bbd0e9
Author: Jonh Wendell <jonh wendell redhat com>
Date:   Fri Sep 9 09:06:05 2016 -0300

    Add g_log_variant(): structured log that accepts a GVariant
    
    This makes the structured logging available to other
    languages via introspection.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=770971

 docs/reference/glib/glib-sections.txt |    1 +
 glib/gmessages.c                      |  110 +++++++++++++++++++++++++++++++++
 glib/gmessages.h                      |    6 ++
 glib/tests/logging.c                  |   56 +++++++++++++++++
 4 files changed, 173 insertions(+), 0 deletions(-)
---
diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
index 30d3132..d8f1643 100644
--- a/docs/reference/glib/glib-sections.txt
+++ b/docs/reference/glib/glib-sections.txt
@@ -1177,6 +1177,7 @@ g_log_set_default_handler
 
 <SUBSECTION>
 g_log_structured
+g_log_variant
 GLogField
 g_log_structured_array
 G_DEBUG_HERE
diff --git a/glib/gmessages.c b/glib/gmessages.c
index db6761f..632547a 100644
--- a/glib/gmessages.c
+++ b/glib/gmessages.c
@@ -1602,6 +1602,116 @@ g_log_structured (const gchar    *log_domain,
   va_end (args);
 }
 
+/**
+ * g_log_variant:
+ * @log_domain: log domain, usually %G_LOG_DOMAIN
+ * @log_level: log level, either from #GLogLevelFlags, or a user-defined
+ *    level
+ * @fields: a dictionary (#GVariant of the type %G_VARIANT_TYPE_VARDICT)
+ * containing the key-value pairs of message data.
+ *
+ * Log a message with structured data, accepting the data within a #GVariant. This
+ * version is especially useful for use in other languages, via introspection.
+ *
+ * The only mandatory item in the @fields dictionary is the "MESSAGE" which must
+ * contain the text shown to the user.
+ *
+ * The values in the @fields dictionary are likely to be of type String
+ * (#G_VARIANT_TYPE_STRING). Array of bytes (#G_VARIANT_TYPE_BYTESTRING) is also
+ * supported. In this case the message is handled as binary and will be forwarded
+ * to the log writer as such. The size of the array should not be higher than
+ * %G_MAXSSIZE. Otherwise it will be truncated to this size. For other types
+ * g_variant_print() will be used to convert the value into a string.
+ *
+ * For more details on its usage and about the parameters, see g_log_structured().
+ *
+ * Since: 2.50
+ */
+
+void
+g_log_variant (const gchar    *log_domain,
+               GLogLevelFlags  log_level,
+               GVariant       *fields)
+{
+  GVariantIter iter;
+  GVariant *value;
+  gchar *key;
+  GArray *fields_array;
+  GLogField field;
+  GSList *values_list, *print_list;
+
+  g_return_if_fail (g_variant_is_of_type (fields, G_VARIANT_TYPE_VARDICT));
+
+  values_list = print_list = NULL;
+  fields_array = g_array_new (FALSE, FALSE, sizeof (GLogField));
+
+  field.key = "PRIORITY";
+  field.value = log_level_to_priority (log_level);
+  field.length = -1;
+  g_array_append_val (fields_array, field);
+
+  if (log_domain)
+    {
+      field.key = "GLIB_DOMAIN";
+      field.value = log_domain;
+      field.length = -1;
+      g_array_append_val (fields_array, field);
+    }
+
+  g_variant_iter_init (&iter, fields);
+  while (g_variant_iter_next (&iter, "{&sv}", &key, &value))
+    {
+      gboolean defer_unref = TRUE;
+
+      field.key = key;
+      field.length = -1;
+
+      if (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
+        {
+          field.value = g_variant_get_string (value, NULL);
+        }
+      else if (g_variant_is_of_type (value, G_VARIANT_TYPE_BYTESTRING))
+        {
+          gsize s;
+          field.value = g_variant_get_fixed_array (value, &s, sizeof (guchar));
+          if (G_LIKELY (s <= G_MAXSSIZE))
+            {
+              field.length = s;
+            }
+          else
+            {
+               _g_fprintf (stderr,
+                           "Byte array too large (%" G_GSIZE_FORMAT " bytes)"
+                           " passed to g_log_variant(). Truncating to " G_STRINGIFY (G_MAXSSIZE)
+                           " bytes.", s);
+              field.length = G_MAXSSIZE;
+            }
+        }
+      else
+        {
+          char *s = g_variant_print (value, FALSE);
+          field.value = s;
+          print_list = g_slist_prepend (print_list, s);
+          defer_unref = FALSE;
+        }
+
+      g_array_append_val (fields_array, field);
+
+      if (G_LIKELY (defer_unref))
+        values_list = g_slist_prepend (values_list, value);
+      else
+        g_variant_unref (value);
+    }
+
+  /* Log it. */
+  g_log_structured_array (log_level, (GLogField *) fields_array->data, fields_array->len);
+
+  g_array_free (fields_array, TRUE);
+  g_slist_free_full (values_list, (GDestroyNotify) g_variant_unref);
+  g_slist_free_full (print_list, g_free);
+}
+
+
 #pragma GCC diagnostic pop
 
 static GLogWriterOutput _g_log_writer_fallback (GLogLevelFlags   log_level,
diff --git a/glib/gmessages.h b/glib/gmessages.h
index 9953652..c923aea 100644
--- a/glib/gmessages.h
+++ b/glib/gmessages.h
@@ -32,6 +32,7 @@
 #include <stdarg.h>
 #include <glib/gtypes.h>
 #include <glib/gmacros.h>
+#include <glib/gvariant.h>
 
 G_BEGIN_DECLS
 
@@ -197,6 +198,11 @@ void             g_log_structured_array        (GLogLevelFlags   log_level,
                                                 gsize            n_fields);
 
 GLIB_AVAILABLE_IN_2_50
+void             g_log_variant                 (const gchar     *log_domain,
+                                                GLogLevelFlags   log_level,
+                                                GVariant        *fields);
+
+GLIB_AVAILABLE_IN_2_50
 void             g_log_set_writer_func         (GLogWriterFunc   func,
                                                 gpointer         user_data,
                                                 GDestroyNotify   user_data_free);
diff --git a/glib/tests/logging.c b/glib/tests/logging.c
index 0821c27..da41d82 100644
--- a/glib/tests/logging.c
+++ b/glib/tests/logging.c
@@ -345,6 +345,8 @@ compare_fields (const GLogField *f1, gsize n1, const GLogField *f2, gsize n2)
 }
 
 static GSList *expected_messages = NULL;
+static const guchar binary_field[] = {1, 2, 3, 4, 5};
+
 
 static GLogWriterOutput
 expect_log_writer (GLogLevelFlags   log_level,
@@ -500,6 +502,58 @@ test_structured_logging_roundtrip3 (void)
   g_assert (expected_messages == NULL);
 }
 
+static GVariant *
+create_variant_fields (void)
+{
+  GVariant *binary;
+  GVariantBuilder builder;
+
+  binary = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, binary_field, G_N_ELEMENTS (binary_field), sizeof 
(binary_field[0]));
+
+  g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+  g_variant_builder_add (&builder, "{sv}", "MESSAGE_ID", g_variant_new_string 
("06d4df59e6c24647bfe69d2c27ef0b4e"));
+  g_variant_builder_add (&builder, "{sv}", "MESSAGE", g_variant_new_string ("This is a debug message"));
+  g_variant_builder_add (&builder, "{sv}", "MY_APPLICATION_CUSTOM_FIELD", g_variant_new_string ("some debug 
string"));
+  g_variant_builder_add (&builder, "{sv}", "MY_APPLICATION_CUSTOM_FIELD_BINARY", binary);
+
+  return g_variant_builder_end (&builder);
+}
+
+static void
+test_structured_logging_variant1 (void)
+{
+  GVariant *v = create_variant_fields ();
+
+  log_count = 0;
+  g_log_set_writer_func (null_log_writer, NULL, NULL);
+
+  g_log_variant ("some-domain", G_LOG_LEVEL_MESSAGE, v);
+  g_variant_unref (v);
+  g_assert_cmpint (log_count, ==, 1);
+}
+
+static void
+test_structured_logging_variant2 (void)
+{
+  const GLogField fields[] = {
+    { "GLIB_DOMAIN", "some-domain", -1 },
+    { "PRIORITY", "5", -1 },
+    { "MESSAGE", "This is a debug message", -1 },
+    { "MESSAGE_ID", "06d4df59e6c24647bfe69d2c27ef0b4e", -1 },
+    { "MY_APPLICATION_CUSTOM_FIELD", "some debug string", -1 },
+    { "MY_APPLICATION_CUSTOM_FIELD_BINARY", binary_field, sizeof (binary_field) }
+  };
+  ExpectedMessage expected = { fields, 6 };
+  GVariant *v = create_variant_fields ();
+
+  expected_messages = g_slist_append (NULL, &expected);
+  g_log_set_writer_func (expect_log_writer, NULL, NULL);
+
+  g_log_variant ("some-domain", G_LOG_LEVEL_MESSAGE, v);
+  g_variant_unref (v);
+  g_assert (expected_messages == NULL);
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -531,6 +585,8 @@ main (int argc, char *argv[])
   g_test_add_func ("/structured-logging/roundtrip1", test_structured_logging_roundtrip1);
   g_test_add_func ("/structured-logging/roundtrip2", test_structured_logging_roundtrip2);
   g_test_add_func ("/structured-logging/roundtrip3", test_structured_logging_roundtrip3);
+  g_test_add_func ("/structured-logging/variant1", test_structured_logging_variant1);
+  g_test_add_func ("/structured-logging/variant2", test_structured_logging_variant2);
 
   return g_test_run ();
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]