[glib] Add g_log_variant(): structured log that accepts a GVariant
- From: Jonh Wendell <jwendell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib] Add g_log_variant(): structured log that accepts a GVariant
- Date: Fri, 9 Sep 2016 13:26:40 +0000 (UTC)
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]