tracerrecord: add a log record class
authorStefan Sauer <ensonic@users.sf.net>
Tue, 12 Jan 2016 13:59:04 +0000 (14:59 +0100)
committerStefan Sauer <ensonic@users.sf.net>
Fri, 15 Jan 2016 20:54:01 +0000 (21:54 +0100)
We use this class to register tracer log entry metadata and build a log
template. With the log template we can serialize log data very efficiently.
This also simplifies the logging code, since that is now a simple varargs
function that is not exposing the implementation details.

Add docs for the new class and basic tests.

Remove the previous log handler.

Fixes #760267

17 files changed:
docs/gst/gstreamer-docs.sgml
docs/gst/gstreamer-sections.txt
docs/gst/gstreamer.types.in
gst/Makefile.am
gst/gst_private.h
gst/gststructure.c
gst/gsttracer.c
gst/gsttracer.h
gst/gsttracerrecord.c [new file with mode: 0644]
gst/gsttracerrecord.h [new file with mode: 0644]
plugins/tracers/gstlatency.c
plugins/tracers/gstrusage.c
plugins/tracers/gststats.c
tests/check/Makefile.am
tests/check/gst/.gitignore
tests/check/gst/gsttracerrecord.c [new file with mode: 0644]
win32/common/libgstreamer.def

index cf476cd..dfa293b 100644 (file)
@@ -135,6 +135,7 @@ Windows.  It is released under the GNU Library General Public License
     <xi:include href="xml/gstinfo.xml" />
     <xi:include href="xml/gsttracer.xml" />
     <xi:include href="xml/gsttracerfactory.xml" />
+    <xi:include href="xml/gsttracerrecord.xml" />
 
   </chapter>
 
index b15d037..8c04414 100644 (file)
@@ -3047,7 +3047,6 @@ gst_toc_scope_get_type
 GstTracer
 gst_tracer_register
 gst_tracing_register_hook
-gst_tracer_log_trace
 
 GstTracerHookBinAddPost
 GstTracerHookBinAddPre
@@ -3144,6 +3143,26 @@ gst_tracer_factory_get_type
 
 
 <SECTION>
+<FILE>gsttracerrecord</FILE>
+<TITLE>GstTracerRecord</TITLE>
+GstTracerRecord
+gst_tracer_record_new
+gst_tracer_record_log
+<SUBSECTION Standard>
+GstTracerRecordClass
+GST_TRACER_RECORD
+GST_IS_TRACER_RECORD
+GST_TRACER_RECORD_CLASS
+GST_IS_TRACER_RECORD_CLASS
+GST_TRACER_RECORD_GET_CLASS
+GST_TRACER_RECORD_CAST
+GST_TYPE_TRACER_RECORD
+<SUBSECTION Private>
+gst_tracer_record_get_type
+</SECTION>
+
+
+<SECTION>
 <FILE>gsttocsetter</FILE>
 <TITLE>GstTocSetter</TITLE>
 GstTocSetter
index d917301..8522c1e 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <gst/gst.h>
 #include <gst/gsttracer.h>
+#include <gst/gsttracerrecord.h>
 
 gst_bin_get_type
 gst_buffer_pool_get_type
@@ -31,6 +32,7 @@ gst_tag_setter_get_type
 gst_task_get_type
 gst_tracer_get_type
 gst_tracer_factory_get_type
+gst_tracer_record_get_type
 gst_type_find_factory_get_type
 gst_uri_handler_get_type
 
index fa1ea7b..224544c 100644 (file)
@@ -117,6 +117,7 @@ libgstreamer_@GST_API_VERSION@_la_SOURCES = \
        $(GST_TRACE_SRC)        \
        gsttracer.c             \
        gsttracerfactory.c      \
+       gsttracerrecord.c               \
        gsttracerutils.c                \
        gsttypefind.c           \
        gsttypefindfactory.c    \
@@ -223,6 +224,7 @@ gst_headers =                       \
        gsttocsetter.h          \
        gsttracer.h             \
        gsttracerfactory.h      \
+       gsttracerrecord.h               \
        gsttypefind.h           \
        gsttypefindfactory.h    \
        gsturi.h                \
index c8cdda9..ac0b1b5 100644 (file)
@@ -151,6 +151,11 @@ G_GNUC_INTERNAL
 gboolean  priv_gst_structure_append_to_gstring (const GstStructure * structure,
                                                 GString            * s);
 G_GNUC_INTERNAL
+gboolean priv__gst_structure_append_template_to_gstring (GQuark field_id,
+                                                        const GValue *value,
+                                                        gpointer user_data);
+
+G_GNUC_INTERNAL
 void priv_gst_caps_features_append_to_gstring (const GstCapsFeatures * features, GString *s);
 
 G_GNUC_INTERNAL
index 2f8fc95..08a82fc 100644 (file)
@@ -1877,7 +1877,7 @@ gst_structure_to_abbr (GType type)
 }
 
 static GType
-gst_structure_value_get_generic_type (GValue * val)
+gst_structure_value_get_generic_type (const GValue * val)
 {
   if (G_VALUE_TYPE (val) == GST_TYPE_LIST
       || G_VALUE_TYPE (val) == GST_TYPE_ARRAY) {
@@ -1941,6 +1941,50 @@ priv_gst_structure_append_to_gstring (const GstStructure * structure,
   return TRUE;
 }
 
+gboolean
+priv__gst_structure_append_template_to_gstring (GQuark field_id,
+    const GValue * value, gpointer user_data)
+{
+  GType type = gst_structure_value_get_generic_type (value);
+  GString *s = (GString *) user_data;
+
+  g_string_append_len (s, ", ", 2);
+  /* FIXME: do we need to escape fieldnames? */
+  g_string_append (s, g_quark_to_string (field_id));
+  g_string_append_len (s, "=(", 2);
+  g_string_append (s, gst_structure_to_abbr (type));
+  g_string_append_c (s, ')');
+
+  //TODO(ensonic): table like GstStructureAbbreviation (or extend it)
+  if (type == G_TYPE_INT) {
+    g_string_append_len (s, "%i", 2);
+  } else if (type == G_TYPE_UINT) {
+    g_string_append_len (s, "%u", 2);
+  } else if (type == G_TYPE_FLOAT) {
+    g_string_append_len (s, "%f", 2);
+  } else if (type == G_TYPE_DOUBLE) {
+    g_string_append_len (s, "%lf", 3);
+  } else if (type == G_TYPE_STRING) {
+    g_string_append_len (s, "%s", 2);
+  } else if (type == G_TYPE_BOOLEAN) {
+    /* we normally store this as a string, but can parse it also from an int */
+    g_string_append_len (s, "%i", 2);
+  } else if (type == G_TYPE_INT64) {
+    g_string_append (s, "%" G_GINT64_FORMAT);
+  } else if (type == G_TYPE_UINT64) {
+    g_string_append (s, "%" G_GUINT64_FORMAT);
+  } else if (type == GST_TYPE_STRUCTURE) {
+    g_string_append (s, "%" GST_PTR_FORMAT);
+  } else if (g_type_is_a (type, G_TYPE_ENUM)) {
+    g_string_append (s, "%i");
+  } else {
+    GST_WARNING ("unhandled type: %s", g_type_name (type));
+    g_string_append (s, "%" GST_PTR_FORMAT);
+  }
+
+  return TRUE;
+}
+
 /**
  * gst_structure_to_string:
  * @structure: a #GstStructure
index 8cb9357..e5645dc 100644 (file)
@@ -194,38 +194,3 @@ gst_tracer_register (GstPlugin * plugin, const gchar * name, GType type)
 
   return TRUE;
 }
-
-/* tracing module helpers */
-
-/**
- * gst_tracer_log_trace:
- *
- * Default log hander for traces. Serialzed the trace event into the log.
- *
- * Right now this is using the gstreamer debug log with the level TRACE (7) and
- * the category "GST_TRACER".
- * <note><para>
- *   Please note that this is still under discussion and subject to change.
- * </para></note>
- */
-void
-gst_tracer_log_trace (GstStructure * s)
-{
-  GST_TRACE ("%" GST_PTR_FORMAT, s);
-  /* expands to:
-     gst_debug_log_valist (
-     GST_CAT_DEFAULT, GST_LEVEL_TRACE,
-     file, func, line, object
-     "%" GST_PTR_FORMAT, s);
-     // does it make sense to use the {file, line, func} from the tracer hook?
-     // a)
-     // - we'd need to pass them in the macros to gst_tracer_dispatch()
-     // - and each tracer needs to grab them from the va_list and pass them here
-     // b)
-     // - we create a content in dispatch, pass that to the tracer
-     // - and the tracer will pass that here
-     // ideally we also use *our* ts instead of the one that
-     // gst_debug_log_default() will pick
-   */
-  gst_structure_free (s);
-}
index 059433b..cdf1461 100644 (file)
@@ -68,9 +68,6 @@ void gst_tracing_register_hook (GstTracer *tracer, const gchar *detail,
 /* tracing modules */
 gboolean gst_tracer_register (GstPlugin * plugin, const gchar * name, GType type);
 
-/* tracing module helpers */
-void gst_tracer_log_trace (GstStructure * s);
-
 #ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstTracer, gst_object_unref)
 #endif
diff --git a/gst/gsttracerrecord.c b/gst/gsttracerrecord.c
new file mode 100644 (file)
index 0000000..060aead
--- /dev/null
@@ -0,0 +1,251 @@
+/* GStreamer
+ * Copyright (C) 2016 Stefan Sauer <ensonic@users.sf.net>
+ *
+ * gsttracerrecord.c: tracer log record class
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:gsttracerrecord
+ * @short_description: Trace log entry class
+ *
+ * Tracing modules will create instances of this class to announce the data they
+ * will log and create a log formatter.
+ *
+ * Since: 1.8
+ */
+
+#define GST_USE_UNSTABLE_API
+
+#include "gst_private.h"
+#include "gstinfo.h"
+#include "gststructure.h"
+#include "gsttracerrecord.h"
+#include "gstvalue.h"
+
+GST_DEBUG_CATEGORY_EXTERN (tracer_debug);
+#define GST_CAT_DEFAULT tracer_debug
+
+
+enum
+{
+  PROP_0,
+  PROP_SPEC,
+  PROP_LAST
+};
+
+static GParamSpec *properties[PROP_LAST];
+
+struct _GstTracerRecord
+{
+  GstObject parent;
+
+  GstStructure *spec;
+  gchar *format;
+};
+
+struct _GstTracerRecordClass
+{
+  GstObjectClass parent_class;
+};
+
+#define gst_tracer_record_parent_class parent_class
+G_DEFINE_TYPE (GstTracerRecord, gst_tracer_record, GST_TYPE_OBJECT);
+
+static gboolean
+build_field_template (GQuark field_id, const GValue * value, gpointer user_data)
+{
+  GString *s = (GString *) user_data;
+  const GstStructure *sub;
+  GValue template_value = { 0, };
+  GType type;
+  gboolean res;
+
+  g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_STRUCTURE, FALSE);
+
+  sub = gst_value_get_structure (value);
+  type = g_value_get_gtype (gst_structure_get_value (sub, "type"));
+  g_value_init (&template_value, type);
+
+  res = priv__gst_structure_append_template_to_gstring (field_id,
+      &template_value, s);
+  g_value_unset (&template_value);
+  return res;
+}
+
+static void
+gst_tracer_record_build_format (GstTracerRecord * self)
+{
+  GstStructure *structure = self->spec;
+  GString *s;
+  gchar *name = (gchar *) g_quark_to_string (structure->name);
+  gchar *p;
+
+  g_return_if_fail (g_str_has_suffix (name, ".class"));
+
+  GST_TRACE ("%" GST_PTR_FORMAT, structure);
+
+  /* cut off '.class' suffix */
+  name = g_strdup (name);
+  p = strrchr (name, '.');
+  *p = '\0';
+
+  s = g_string_sized_new (STRUCTURE_ESTIMATED_STRING_LEN (structure));
+  g_string_append (s, name);
+  gst_structure_foreach (structure, build_field_template, s);
+  g_string_append_c (s, ';');
+
+  self->format = g_string_free (s, FALSE);
+  GST_INFO ("new format string: %s", self->format);
+  g_free (name);
+}
+
+static void
+gst_tracer_record_dispose (GObject * object)
+{
+  GstTracerRecord *self = GST_TRACER_RECORD (object);
+
+  gst_structure_free (self->spec);
+  g_free (self->format);
+}
+
+static void
+gst_tracer_record_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstTracerRecord *self = GST_TRACER_RECORD_CAST (object);
+
+  switch (prop_id) {
+    case PROP_SPEC:
+      self->spec = g_value_get_boxed (value);
+      gst_tracer_record_build_format (self);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_tracer_record_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstTracerRecord *self = GST_TRACER_RECORD_CAST (object);
+
+  switch (prop_id) {
+    case PROP_SPEC:
+      // TODO(ensonic): copy?
+      g_value_set_boxed (value, self->spec);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_tracer_record_class_init (GstTracerRecordClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->set_property = gst_tracer_record_set_property;
+  gobject_class->get_property = gst_tracer_record_get_property;
+  gobject_class->dispose = gst_tracer_record_dispose;
+
+  properties[PROP_SPEC] =
+      g_param_spec_boxed ("spec", "Spec", "Log record specification",
+      GST_TYPE_STRUCTURE,
+      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+  g_object_class_install_properties (gobject_class, PROP_LAST, properties);
+}
+
+static void
+gst_tracer_record_init (GstTracerRecord * self)
+{
+}
+
+/**
+ * gst_tracer_record_new:
+ * @spec: the record specification
+ *
+ * Create a new tracer record. The record instance can be used to efficiently
+ * log entries using gst_tracer_record_log().
+ *
+ * The name of the @spec #GstStructure must end on '.class'. This name without
+ * the suffix will be used for the log records. The @spec must have a field for
+ * each value that gets logged where the field name is the value name. The field
+ * must be a nested structure describing the value. The sub structure must
+ * contain a field called 'type' of %G_TYPE_GTYPE that contains the GType of the
+ * value.
+ *
+ * The way to deal with optional values is to log an additional boolean before
+ * the optional field, that if %TRUE signals that the optional field is valid
+ * and %FALSE signals that the optional field should be ignored. One must still
+ * log a placeholder value for the optional field though. Please also note, that
+ * pointer type values must not be NULL - the underlying serialisation can not
+ * handle that right now.
+ *
+ * <note><para>
+ *   Please note that this is still under discussion and subject to change.
+ * </para></note>
+ *
+ * Returns: a new #GstTracerRecord
+ */
+GstTracerRecord *
+gst_tracer_record_new (GstStructure * spec)
+{
+  return g_object_new (GST_TYPE_TRACER_RECORD, "spec", spec, NULL);
+}
+
+/**
+ * gst_tracer_record_log:
+ * @self: the tracer-record
+ * @...: the args as described in the spec-
+ *
+ * Serialzes the trace event into the log.
+ *
+ * Right now this is using the gstreamer debug log with the level TRACE (7) and
+ * the category "GST_TRACER".
+ * <note><para>
+ *   Please note that this is still under discussion and subject to change.
+ * </para></note>
+ */
+void
+gst_tracer_record_log (GstTracerRecord * self, ...)
+{
+  va_list var_args;
+
+  /*
+   * does it make sense to use the {file, line, func} from the tracer hook?
+   * a)
+   * - we'd need to pass them in the macros to gst_tracer_dispatch()
+   * - and each tracer needs to grab them from the va_list and pass them here
+   * b)
+   * - we create a context in dispatch, pass that to the tracer
+   * - and the tracer will pass that here
+   * ideally we also use *our* ts instead of the one that
+   * gst_debug_log_default() will pick
+   */
+
+  va_start (var_args, self);
+  if (G_LIKELY (GST_LEVEL_TRACE <= _gst_debug_min)) {
+    gst_debug_log_valist (GST_CAT_DEFAULT, GST_LEVEL_TRACE, "", "", 0, NULL,
+        self->format, var_args);
+  }
+  va_end (var_args);
+}
diff --git a/gst/gsttracerrecord.h b/gst/gsttracerrecord.h
new file mode 100644 (file)
index 0000000..c69f6e8
--- /dev/null
@@ -0,0 +1,57 @@
+/* GStreamer
+ * Copyright (C) 2016 Stefan Sauer <ensonic@users.sf.net>
+ *
+ * gsttracerrecord.h: tracer log record class
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_TRACER_RECORD_H__
+#define __GST_TRACER_RECORD_H__
+
+#ifndef GST_USE_UNSTABLE_API
+#warning "The tracer subsystem is unstable API and may change in future."
+#warning "You can define GST_USE_UNSTABLE_API to avoid this warning."
+#endif
+
+#include <gst/gstobject.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstTracerRecord GstTracerRecord;
+typedef struct _GstTracerRecordPrivate GstTracerRecordPrivate;
+typedef struct _GstTracerRecordClass GstTracerRecordClass;
+
+#define GST_TYPE_TRACER_RECORD            (gst_tracer_record_get_type())
+#define GST_TRACER_RECORD(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_TRACER_RECORD,GstTracerRecord))
+#define GST_TRACER_RECORD_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_TRACER_RECORD,GstTracerRecordClass))
+#define GST_IS_TRACER_RECORD(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_TRACER_RECORD))
+#define GST_IS_TRACER_RECORD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_TRACER_RECORD))
+#define GST_TRACER_RECORD_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_TRACER_RECORD,GstTracerRecordClass))
+#define GST_TRACER_RECORD_CAST(obj)       ((GstTracerRecord *)(obj))
+
+GType gst_tracer_record_get_type          (void);
+
+GstTracerRecord * gst_tracer_record_new (GstStructure *spec);
+void gst_tracer_record_log (GstTracerRecord *self, ...);
+
+#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstTracerRecord, gst_object_unref)
+#endif
+
+G_END_DECLS
+
+#endif /* __GST_TRACER_RECORD_H__ */
index 1edd1a5..93d93eb 100644 (file)
@@ -38,6 +38,7 @@
 #endif
 
 #include "gstlatency.h"
+#include <gst/gsttracerrecord.h>
 
 GST_DEBUG_CATEGORY_STATIC (gst_latency_debug);
 #define GST_CAT_DEFAULT gst_latency_debug
@@ -52,6 +53,8 @@ static GQuark latency_probe_id;
 static GQuark latency_probe_pad;
 static GQuark latency_probe_ts;
 
+static GstTracerRecord *tr_latency;
+
 /* data helpers */
 
 /*
@@ -103,11 +106,8 @@ log_latency (const GstStructure * data, GstPad * sink_pad, guint64 sink_ts)
   src = g_strdup_printf ("%s_%s", GST_DEBUG_PAD_NAME (src_pad));
   sink = g_strdup_printf ("%s_%s", GST_DEBUG_PAD_NAME (sink_pad));
 
-  /* TODO(ensonic): report format is still unstable */
-  gst_tracer_log_trace (gst_structure_new ("latency",
-          "src", G_TYPE_STRING, src,
-          "sink", G_TYPE_STRING, sink,
-          "time", G_TYPE_UINT64, GST_CLOCK_DIFF (src_ts, sink_ts), NULL));
+  gst_tracer_record_log (tr_latency, src, sink,
+      GST_CLOCK_DIFF (src_ts, sink_ts));
   g_free (src);
   g_free (sink);
 }
@@ -204,11 +204,13 @@ gst_latency_tracer_class_init (GstLatencyTracerClass * klass)
 
   /* announce trace formats */
   /* *INDENT-OFF* */
-  gst_tracer_log_trace (gst_structure_new ("latency.class",
+  tr_latency = gst_tracer_record_new (gst_structure_new ("latency.class",
       "src", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
+          "type", G_TYPE_GTYPE, G_TYPE_STRING,
           "related-to", G_TYPE_STRING, "pad",  /* TODO: use genum */
           NULL),
       "sink", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
+          "type", G_TYPE_GTYPE, G_TYPE_STRING,
           "related-to", G_TYPE_STRING, "pad",  /* TODO: use genum */
           NULL),
       "time", GST_TYPE_STRUCTURE, gst_structure_new ("value",
index 3db1011..c455dab 100644 (file)
@@ -22,7 +22,7 @@
  * SECTION:gstrusage
  * @short_description: log resource usage stats
  *
- * A tracing module that take rusage() snapshots and logs them. 
+ * A tracing module that take rusage() snapshots and logs them.
  */
 
 #ifdef HAVE_CONFIG_H
@@ -31,6 +31,7 @@
 
 #include <unistd.h>
 #include "gstrusage.h"
+#include <gst/gsttracerrecord.h>
 
 #ifdef HAVE_SYS_RESOURCE_H
 #ifndef __USE_GNU
@@ -56,6 +57,8 @@ G_DEFINE_TYPE_WITH_CODE (GstRUsageTracer, gst_rusage_tracer, GST_TYPE_TRACER,
 /* number of cpus to scale cpu-usage in threads */
 static glong num_cpus = 1;
 
+static GstTracerRecord *tr_proc, *tr_thread;
+
 typedef struct
 {
   /* time spend in this thread */
@@ -236,13 +239,8 @@ do_stats (GstTracer * obj, guint64 ts)
   update_trace_value (stats->tvs_thread, ts, stats->tthread, &dts, &dtproc);
   cur_cpuload = (guint) gst_util_uint64_scale (dtproc,
       G_GINT64_CONSTANT (1000), dts);
-  gst_tracer_log_trace (gst_structure_new ("thread-rusage", 
-      "ts", G_TYPE_UINT64, ts, 
-      "thread-id", G_TYPE_UINT, GPOINTER_TO_UINT (thread_id), 
-      "average-cpuload", G_TYPE_UINT, MIN (avg_cpuload, 1000),
-      "current-cpuload", G_TYPE_UINT, MIN (cur_cpuload, 1000),
-      "time", G_TYPE_UINT64, stats->tthread,
-      NULL));
+  gst_tracer_record_log (tr_thread, (guint64)thread_id, ts,
+      MIN (avg_cpuload, 1000), MIN (cur_cpuload, 1000), stats->tthread);
 
   avg_cpuload = (guint) gst_util_uint64_scale (tproc / num_cpus,
       G_GINT64_CONSTANT (1000), ts);
@@ -251,12 +249,8 @@ do_stats (GstTracer * obj, guint64 ts)
   G_UNLOCK (_proc);
   cur_cpuload = (guint) gst_util_uint64_scale (dtproc / num_cpus,
       G_GINT64_CONSTANT (1000), dts);
-  gst_tracer_log_trace (gst_structure_new ("proc-rusage", 
-      "ts", G_TYPE_UINT64, ts, 
-      "average-cpuload", G_TYPE_UINT, MIN (avg_cpuload, 1000),
-      "current-cpuload", G_TYPE_UINT, MIN (cur_cpuload, 1000),
-      "time", G_TYPE_UINT64, tproc,
-      NULL));
+  gst_tracer_record_log (tr_proc, ts, MIN (avg_cpuload, 1000),
+      MIN (cur_cpuload, 1000), tproc);
   /* *INDENT-ON* */
 }
 
@@ -291,54 +285,64 @@ gst_rusage_tracer_class_init (GstRUsageTracerClass * klass)
 
   /* announce trace formats */
   /* *INDENT-OFF* */
-  gst_tracer_log_trace (gst_structure_new ("thread-rusage.class",
+  tr_thread = gst_tracer_record_new (gst_structure_new ("thread-rusage.class",
       "thread-id", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
+          "type", G_TYPE_GTYPE, G_TYPE_UINT64,
           "related-to", G_TYPE_STRING, "thread",  /* TODO: use genum */
           NULL),
+      "ts", GST_TYPE_STRUCTURE, gst_structure_new ("value",
+          "type", G_TYPE_GTYPE, G_TYPE_UINT64,
+          "description", G_TYPE_STRING, "event ts",
+          NULL),
       "average-cpuload", GST_TYPE_STRUCTURE, gst_structure_new ("value",
           "type", G_TYPE_GTYPE, G_TYPE_UINT,
           "description", G_TYPE_STRING, "average cpu usage per thread in â€°",
-          "flags", G_TYPE_STRING, "aggregated",  /* TODO: use gflags */ 
-          "min", G_TYPE_UINT, 0, 
+          "flags", G_TYPE_STRING, "aggregated",  /* TODO: use gflags */
+          "min", G_TYPE_UINT, 0,
           "max", G_TYPE_UINT, 1000,
           NULL),
       "current-cpuload", GST_TYPE_STRUCTURE, gst_structure_new ("value",
           "type", G_TYPE_GTYPE, G_TYPE_UINT,
           "description", G_TYPE_STRING, "current cpu usage per thread in â€°",
-          "flags", G_TYPE_STRING, "windowed",  /* TODO: use gflags */ 
-          "min", G_TYPE_UINT, 0, 
+          "flags", G_TYPE_STRING, "windowed",  /* TODO: use gflags */
+          "min", G_TYPE_UINT, 0,
           "max", G_TYPE_UINT, 1000,
           NULL),
       "time", GST_TYPE_STRUCTURE, gst_structure_new ("value",
           "type", G_TYPE_GTYPE, G_TYPE_UINT64,
           "description", G_TYPE_STRING, "time spent in thread in ns",
-          "flags", G_TYPE_STRING, "aggregated",  /* TODO: use gflags */ 
+          "flags", G_TYPE_STRING, "aggregated",  /* TODO: use gflags */
           "min", G_TYPE_UINT64, G_GUINT64_CONSTANT (0),
           "max", G_TYPE_UINT64, G_MAXUINT64,
           NULL),
       NULL));
-  gst_tracer_log_trace (gst_structure_new ("proc-rusage.class",
+  tr_proc = gst_tracer_record_new (gst_structure_new ("proc-rusage.class",
       "thread-id", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
+          "type", G_TYPE_GTYPE, G_TYPE_UINT64,
           "related-to", G_TYPE_STRING, "process",  /* TODO: use genum */
           NULL),
+      "ts", GST_TYPE_STRUCTURE, gst_structure_new ("value",
+          "type", G_TYPE_GTYPE, G_TYPE_UINT64,
+          "description", G_TYPE_STRING, "event ts",
+          NULL),
       "average-cpuload", GST_TYPE_STRUCTURE, gst_structure_new ("value",
           "type", G_TYPE_GTYPE, G_TYPE_UINT,
           "description", G_TYPE_STRING, "average cpu usage per process in â€°",
-          "flags", G_TYPE_STRING, "aggregated",  /* TODO: use gflags */ 
-          "min", G_TYPE_UINT, 0, 
+          "flags", G_TYPE_STRING, "aggregated",  /* TODO: use gflags */
+          "min", G_TYPE_UINT, 0,
           "max", G_TYPE_UINT, 1000,
           NULL),
       "current-cpuload", GST_TYPE_STRUCTURE, gst_structure_new ("value",
           "type", G_TYPE_GTYPE, G_TYPE_UINT,
           "description", G_TYPE_STRING, "current cpu usage per process in â€°",
-          "flags", G_TYPE_STRING, "windowed",  /* TODO: use gflags */ 
-          "min", G_TYPE_UINT, 0, 
+          "flags", G_TYPE_STRING, "windowed",  /* TODO: use gflags */
+          "min", G_TYPE_UINT, 0,
           "max", G_TYPE_UINT, 1000,
           NULL),
       "time", GST_TYPE_STRUCTURE, gst_structure_new ("value",
           "type", G_TYPE_GTYPE, G_TYPE_UINT64,
           "description", G_TYPE_STRING, "time spent in process in ns",
-          "flags", G_TYPE_STRING, "aggregated",  /* TODO: use gflags */ 
+          "flags", G_TYPE_STRING, "aggregated",  /* TODO: use gflags */
           "min", G_TYPE_UINT64, G_GUINT64_CONSTANT (0),
           "max", G_TYPE_UINT64, G_MAXUINT64,
           NULL),
index 1c93123..87c1927 100644 (file)
@@ -30,6 +30,7 @@
 #endif
 
 #include "gststats.h"
+#include <gst/gsttracerrecord.h>
 
 #include <stdio.h>
 
@@ -47,6 +48,14 @@ G_LOCK_DEFINE (_pad_stats);
 G_DEFINE_TYPE_WITH_CODE (GstStatsTracer, gst_stats_tracer, GST_TYPE_TRACER,
     _do_init);
 
+static GstTracerRecord *tr_new_element;
+static GstTracerRecord *tr_new_pad;
+static GstTracerRecord *tr_buffer;
+static GstTracerRecord *tr_element_query;
+static GstTracerRecord *tr_event;
+static GstTracerRecord *tr_message;
+static GstTracerRecord *tr_query;
+
 typedef struct
 {
   /* we can't rely on the address to be unique over time */
@@ -87,14 +96,9 @@ static void
 log_new_element_stats (GstElementStats * stats, GstElement * element,
     GstClockTime elapsed)
 {
-  gst_tracer_log_trace (gst_structure_new ("new-element",
-          "thread-id", G_TYPE_UINT, GPOINTER_TO_UINT (g_thread_self ()),
-          "ts", G_TYPE_UINT64, elapsed,
-          "ix", G_TYPE_UINT, stats->index,
-          "parent-ix", G_TYPE_UINT, stats->parent_ix,
-          "name", G_TYPE_STRING, GST_OBJECT_NAME (element),
-          "type", G_TYPE_STRING, G_OBJECT_TYPE_NAME (element),
-          "is-bin", G_TYPE_BOOLEAN, GST_IS_BIN (element), NULL));
+  gst_tracer_record_log (tr_new_element, (guint64) g_thread_self (),
+      elapsed, stats->index, stats->parent_ix, GST_OBJECT_NAME (element),
+      G_OBJECT_TYPE_NAME (element), GST_IS_BIN (element));
 }
 
 static void
@@ -194,15 +198,10 @@ fill_pad_stats (GstStatsTracer * self, GstPad * pad)
 static void
 log_new_pad_stats (GstPadStats * stats, GstPad * pad)
 {
-  gst_tracer_log_trace (gst_structure_new ("new-pad",
-          "thread-id", G_TYPE_UINT, GPOINTER_TO_UINT (g_thread_self ()),
-          "ix", G_TYPE_UINT, stats->index,
-          "parent-ix", G_TYPE_UINT, stats->parent_ix,
-          "name", G_TYPE_STRING, GST_OBJECT_NAME (pad),
-          "type", G_TYPE_STRING, G_OBJECT_TYPE_NAME (pad),
-          "is-ghostpad", G_TYPE_BOOLEAN, GST_IS_GHOST_PAD (pad),
-          "pad-direction", GST_TYPE_PAD_DIRECTION, GST_PAD_DIRECTION (pad),
-          NULL));
+  gst_tracer_record_log (tr_new_element, (guint64) g_thread_self (),
+      stats->index, stats->parent_ix, GST_OBJECT_NAME (pad),
+      G_OBJECT_TYPE_NAME (pad), GST_IS_GHOST_PAD (pad),
+      GST_PAD_DIRECTION (pad));
 }
 
 static void
@@ -254,50 +253,27 @@ do_buffer_stats (GstStatsTracer * self, GstPad * this_pad,
   GstElement *that_elem = get_real_pad_parent (that_pad);
   GstElementStats *that_elem_stats = get_element_stats (self, that_elem);
 
-  /* TODO(ensonic): need a quark-table (shared with the tracer-front-ends?) */
-  gst_tracer_log_trace (gst_structure_new ("buffer",
-          "thread-id", G_TYPE_UINT, GPOINTER_TO_UINT (g_thread_self ()),
-          "ts", G_TYPE_UINT64, elapsed,
-          "pad-ix", G_TYPE_UINT, this_pad_stats->index,
-          "elem-ix", G_TYPE_UINT, this_elem_stats->index,
-          "peer-pad-ix", G_TYPE_UINT, that_pad_stats->index,
-          "peer-elem-ix", G_TYPE_UINT, that_elem_stats->index,
-          "buffer-size", G_TYPE_UINT, gst_buffer_get_size (buf),
-          "buffer-pts", G_TYPE_UINT64, GST_BUFFER_PTS (buf),
-          "buffer-dts", G_TYPE_UINT64, GST_BUFFER_DTS (buf),
-          "buffer-duration", G_TYPE_UINT64, GST_BUFFER_DURATION (buf),
-          "buffer-flags", GST_TYPE_BUFFER_FLAGS, GST_BUFFER_FLAGS (buf),
-          /*
-             scheduling-jitter: for this we need the last_ts on the pad
-           */
-          NULL));
+  gst_tracer_record_log (tr_buffer, (guint64) g_thread_self (), elapsed,
+      this_pad_stats->index, this_elem_stats->index, that_pad_stats->index,
+      that_elem_stats->index, gst_buffer_get_size (buf), GST_BUFFER_PTS (buf),
+      GST_BUFFER_DTS (buf), GST_BUFFER_DURATION (buf), GST_BUFFER_FLAGS (buf));
 }
 
 static void
 do_query_stats (GstStatsTracer * self, GstPad * this_pad,
     GstPadStats * this_pad_stats, GstPad * that_pad,
     GstPadStats * that_pad_stats, GstQuery * qry, GstClockTime elapsed,
-    gboolean res, gboolean is_post)
+    gboolean have_res, gboolean res)
 {
   GstElement *this_elem = get_real_pad_parent (this_pad);
   GstElementStats *this_elem_stats = get_element_stats (self, this_elem);
   GstElement *that_elem = get_real_pad_parent (that_pad);
   GstElementStats *that_elem_stats = get_element_stats (self, that_elem);
-  GstStructure *s;
-
-  s = gst_structure_new ("query",
-      "thread-id", G_TYPE_UINT, GPOINTER_TO_UINT (g_thread_self ()),
-      "ts", G_TYPE_UINT64, elapsed,
-      "pad-ix", G_TYPE_UINT, this_pad_stats->index,
-      "elem-ix", G_TYPE_UINT, this_elem_stats->index,
-      "peer-pad-ix", G_TYPE_UINT, that_pad_stats->index,
-      "peer-elem-ix", G_TYPE_UINT, that_elem_stats->index,
-      "name", G_TYPE_STRING, GST_QUERY_TYPE_NAME (qry),
-      "structure", GST_TYPE_STRUCTURE, gst_query_get_structure (qry), NULL);
-  if (is_post) {
-    gst_structure_set (s, "res", G_TYPE_BOOLEAN, res, NULL);
-  }
-  gst_tracer_log_trace (s);
+
+  gst_tracer_record_log (tr_query, (guint64) g_thread_self (), elapsed,
+      this_pad_stats->index, this_elem_stats->index, that_pad_stats->index,
+      that_elem_stats->index, GST_QUERY_TYPE_NAME (qry),
+      gst_query_get_structure (qry), have_res, res);
 }
 
 static void
@@ -473,12 +449,8 @@ do_push_event_pre (GstStatsTracer * self, guint64 ts, GstPad * pad,
   GstPadStats *pad_stats = get_pad_stats (self, pad);
 
   elem_stats->last_ts = ts;
-  gst_tracer_log_trace (gst_structure_new ("event",
-          "thread-id", G_TYPE_UINT, GPOINTER_TO_UINT (g_thread_self ()),
-          "ts", G_TYPE_UINT64, ts,
-          "pad-ix", G_TYPE_UINT, pad_stats->index,
-          "elem-ix", G_TYPE_UINT, elem_stats->index,
-          "name", G_TYPE_STRING, GST_EVENT_TYPE_NAME (ev), NULL));
+  gst_tracer_record_log (tr_event, (guint64) g_thread_self (), ts,
+      pad_stats->index, elem_stats->index, GST_EVENT_TYPE_NAME (ev));
 }
 
 static void
@@ -487,19 +459,11 @@ do_post_message_pre (GstStatsTracer * self, guint64 ts, GstElement * elem,
 {
   GstElementStats *stats = get_element_stats (self, elem);
   const GstStructure *msg_s = gst_message_get_structure (msg);
-  GstStructure *s;
 
   stats->last_ts = ts;
-
-  s = gst_structure_new ("message",
-      "thread-id", G_TYPE_UINT, GPOINTER_TO_UINT (g_thread_self ()),
-      "ts", G_TYPE_UINT64, ts,
-      "elem-ix", G_TYPE_UINT, stats->index,
-      "name", G_TYPE_STRING, GST_MESSAGE_TYPE_NAME (msg), NULL);
-  if (msg_s) {
-    gst_structure_set (s, "structure", GST_TYPE_STRUCTURE, msg_s, NULL);
-  }
-  gst_tracer_log_trace (s);
+  gst_tracer_record_log (tr_message, (guint64) g_thread_self (), ts,
+      stats->index, GST_MESSAGE_TYPE_NAME (msg),
+      (msg_s ? msg_s : gst_structure_new_empty ("dummy")));
 }
 
 static void
@@ -518,11 +482,8 @@ do_element_query_pre (GstStatsTracer * self, guint64 ts, GstElement * elem,
   GstElementStats *stats = get_element_stats (self, elem);
 
   stats->last_ts = ts;
-  gst_tracer_log_trace (gst_structure_new ("element-query",
-          "thread-id", G_TYPE_UINT, GPOINTER_TO_UINT (g_thread_self ()),
-          "ts", G_TYPE_UINT64, ts,
-          "elem-ix", G_TYPE_UINT, stats->index,
-          "name", G_TYPE_STRING, GST_QUERY_TYPE_NAME (qry), NULL));
+  gst_tracer_record_log (tr_element_query, (guint64) g_thread_self (), ts,
+      stats->index, GST_QUERY_TYPE_NAME (qry));
 }
 
 static void
@@ -546,7 +507,7 @@ do_query_post (GstStatsTracer * self, guint64 ts, GstPad * this_pad,
   GstPadStats *that_pad_stats = get_pad_stats (self, that_pad);
 
   do_query_stats (self, this_pad, this_pad_stats, that_pad, that_pad_stats,
-      qry, ts, res, TRUE);
+      qry, ts, TRUE, res);
 }
 
 /* tracer class */
@@ -556,20 +517,29 @@ gst_stats_tracer_class_init (GstStatsTracerClass * klass)
 {
   /* announce trace formats */
   /* *INDENT-OFF* */
-  gst_tracer_log_trace (gst_structure_new ("buffer.class",
+  tr_buffer = gst_tracer_record_new (gst_structure_new ("buffer.class",
       "thread-id", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
+          "type", G_TYPE_GTYPE, G_TYPE_UINT64,
           "related-to", G_TYPE_STRING, "thread", /* TODO use genum */
           NULL),
+      "ts", GST_TYPE_STRUCTURE, gst_structure_new ("value",
+          "type", G_TYPE_GTYPE, G_TYPE_UINT64,
+          "description", G_TYPE_STRING, "event ts",
+          NULL),
       "pad-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
+          "type", G_TYPE_GTYPE, G_TYPE_UINT,
           "related-to", G_TYPE_STRING, "pad",  /* TODO: use genum */
           NULL),
       "element-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
+          "type", G_TYPE_GTYPE, G_TYPE_UINT,
           "related-to", G_TYPE_STRING, "element",  /* TODO: use genum */
           NULL),
       "peer-pad-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
+          "type", G_TYPE_GTYPE, G_TYPE_UINT,
           "related-to", G_TYPE_STRING, "pad",  /* TODO: use genum */
           NULL),
       "peer-element-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
+          "type", G_TYPE_GTYPE, G_TYPE_UINT,
           "related-to", G_TYPE_STRING, "element",  /* TODO: use genum */
           NULL),
       "buffer-size", GST_TYPE_STRUCTURE, gst_structure_new ("value",
@@ -595,14 +565,21 @@ gst_stats_tracer_class_init (GstStatsTracerClass * klass)
           NULL),
       /* TODO(ensonic): "buffer-flags" */
       NULL));
-  gst_tracer_log_trace (gst_structure_new ("event.class",
+  tr_event = gst_tracer_record_new (gst_structure_new ("event.class",
       "thread-id", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
+          "type", G_TYPE_GTYPE, G_TYPE_UINT64,
           "related-to", G_TYPE_STRING, "thread", /* TODO use genum */
           NULL),
+      "ts", GST_TYPE_STRUCTURE, gst_structure_new ("value",
+          "type", G_TYPE_GTYPE, G_TYPE_UINT64,
+          "description", G_TYPE_STRING, "event ts",
+          NULL),
       "pad-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
+          "type", G_TYPE_GTYPE, G_TYPE_UINT,
           "related-to", G_TYPE_STRING, "pad",  /* TODO: use genum */
           NULL),
       "element-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
+          "type", G_TYPE_GTYPE, G_TYPE_UINT,
           "related-to", G_TYPE_STRING, "element",  /* TODO: use genum */
           NULL),
       "name", GST_TYPE_STRUCTURE, gst_structure_new ("value",
@@ -611,11 +588,17 @@ gst_stats_tracer_class_init (GstStatsTracerClass * klass)
           "flags", G_TYPE_STRING, "",  /* TODO: use gflags */
           NULL),
       NULL));
-  gst_tracer_log_trace (gst_structure_new ("message.class",
+  tr_message = gst_tracer_record_new (gst_structure_new ("message.class",
       "thread-id", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
+          "type", G_TYPE_GTYPE, G_TYPE_UINT64,
           "related-to", G_TYPE_STRING, "thread", /* TODO use genum */
           NULL),
+      "ts", GST_TYPE_STRUCTURE, gst_structure_new ("value",
+          "type", G_TYPE_GTYPE, G_TYPE_UINT64,
+          "description", G_TYPE_STRING, "event ts",
+          NULL),
       "element-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
+          "type", G_TYPE_GTYPE, G_TYPE_UINT,
           "related-to", G_TYPE_STRING, "element",  /* TODO: use genum */
           NULL),
       "name", GST_TYPE_STRUCTURE, gst_structure_new ("value",
@@ -628,11 +611,18 @@ gst_stats_tracer_class_init (GstStatsTracerClass * klass)
           "description", G_TYPE_STRING, "message structure",
           NULL),
       NULL));
-  gst_tracer_log_trace (gst_structure_new ("element-query.class",
+  tr_element_query = gst_tracer_record_new (gst_structure_new (
+      "element-query.class",
       "thread-id", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
+          "type", G_TYPE_GTYPE, G_TYPE_UINT64,
           "related-to", G_TYPE_STRING, "thread", /* TODO use genum */
           NULL),
+      "ts", GST_TYPE_STRUCTURE, gst_structure_new ("value",
+          "type", G_TYPE_GTYPE, G_TYPE_UINT64,
+          "description", G_TYPE_STRING, "event ts",
+          NULL),
       "element-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
+          "type", G_TYPE_GTYPE, G_TYPE_UINT,
           "related-to", G_TYPE_STRING, "element",  /* TODO: use genum */
           NULL),
       "name", GST_TYPE_STRUCTURE, gst_structure_new ("value",
@@ -641,20 +631,29 @@ gst_stats_tracer_class_init (GstStatsTracerClass * klass)
           "flags", G_TYPE_STRING, "",  /* TODO: use gflags */
           NULL),
       NULL));
-  gst_tracer_log_trace (gst_structure_new ("query.class",
+  tr_query = gst_tracer_record_new (gst_structure_new ("query.class",
       "thread-id", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
+          "type", G_TYPE_GTYPE, G_TYPE_UINT64,
           "related-to", G_TYPE_STRING, "thread", /* TODO use genum */
           NULL),
+      "ts", GST_TYPE_STRUCTURE, gst_structure_new ("value",
+          "type", G_TYPE_GTYPE, G_TYPE_UINT64,
+          "description", G_TYPE_STRING, "event ts",
+          NULL),
       "pad-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
+          "type", G_TYPE_GTYPE, G_TYPE_UINT,
           "related-to", G_TYPE_STRING, "pad",  /* TODO: use genum */
           NULL),
       "element-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
+          "type", G_TYPE_GTYPE, G_TYPE_UINT,
           "related-to", G_TYPE_STRING, "element",  /* TODO: use genum */
           NULL),
       "peer-pad-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
+          "type", G_TYPE_GTYPE, G_TYPE_UINT,
           "related-to", G_TYPE_STRING, "pad",  /* TODO: use genum */
           NULL),
       "peer-element-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
+          "type", G_TYPE_GTYPE, G_TYPE_UINT,
           "related-to", G_TYPE_STRING, "element",  /* TODO: use genum */
           NULL),
       "name", GST_TYPE_STRUCTURE, gst_structure_new ("value",
@@ -667,8 +666,81 @@ gst_stats_tracer_class_init (GstStatsTracerClass * klass)
           "description", G_TYPE_STRING, "query structure",
           "flags", G_TYPE_STRING, "",  /* TODO: use gflags */
           NULL),
+      "have-res", GST_TYPE_STRUCTURE, gst_structure_new ("value",
+          "type", G_TYPE_GTYPE, G_TYPE_BOOLEAN,
+          "description", G_TYPE_STRING, "have query result",
+          NULL),
+      "res", GST_TYPE_STRUCTURE, gst_structure_new ("value",
+          "type", G_TYPE_GTYPE, G_TYPE_BOOLEAN,
+          "description", G_TYPE_STRING, "query result",
+          NULL),
       /* TODO(ensonic): "buffer-flags" */
       NULL));
+  tr_new_element = gst_tracer_record_new (gst_structure_new (
+      "new-element.class",
+      "thread-id", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
+          "type", G_TYPE_GTYPE, G_TYPE_UINT64,
+          "related-to", G_TYPE_STRING, "thread", /* TODO use genum */
+          NULL),
+      "ts", GST_TYPE_STRUCTURE, gst_structure_new ("value",
+          "type", G_TYPE_GTYPE, G_TYPE_UINT64,
+          "description", G_TYPE_STRING, "event ts",
+          NULL),
+      "ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
+          "type", G_TYPE_GTYPE, G_TYPE_UINT,
+          "related-to", G_TYPE_STRING, "element",  /* TODO: use genum */
+          NULL),
+      "parent-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
+          "type", G_TYPE_GTYPE, G_TYPE_UINT,
+          "related-to", G_TYPE_STRING, "element",  /* TODO: use genum */
+          NULL),
+      "name", GST_TYPE_STRUCTURE, gst_structure_new ("value",
+          "type", G_TYPE_GTYPE, G_TYPE_STRING,
+          "description", G_TYPE_STRING, "name of the element",
+          "flags", G_TYPE_STRING, "",  /* TODO: use gflags */
+          NULL),
+      "type", GST_TYPE_STRUCTURE, gst_structure_new ("value",
+          "type", G_TYPE_GTYPE, G_TYPE_STRING,
+          "description", G_TYPE_STRING, "type name of the element",
+          "flags", G_TYPE_STRING, "",  /* TODO: use gflags */
+          NULL),
+      "is-bin", GST_TYPE_STRUCTURE, gst_structure_new ("value",
+          "type", G_TYPE_GTYPE, G_TYPE_BOOLEAN,
+          "description", G_TYPE_STRING, "is element a bin",
+          NULL),
+      NULL));
+  tr_new_pad = gst_tracer_record_new (gst_structure_new ("new-pad.class",
+      "thread-id", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
+          "type", G_TYPE_GTYPE, G_TYPE_UINT64,
+          "related-to", G_TYPE_STRING, "thread", /* TODO use genum */
+          NULL),
+      "ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
+          "type", G_TYPE_GTYPE, G_TYPE_UINT,
+          "related-to", G_TYPE_STRING, "pad",  /* TODO: use genum */
+          NULL),
+      "parent-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
+          "type", G_TYPE_GTYPE, G_TYPE_UINT,
+          "related-to", G_TYPE_STRING, "element",  /* TODO: use genum */
+          NULL),
+      "name", GST_TYPE_STRUCTURE, gst_structure_new ("value",
+          "type", G_TYPE_GTYPE, G_TYPE_STRING,
+          "description", G_TYPE_STRING, "name of the pad",
+          "flags", G_TYPE_STRING, "",  /* TODO: use gflags */
+          NULL),
+      "type", GST_TYPE_STRUCTURE, gst_structure_new ("value",
+          "type", G_TYPE_GTYPE, G_TYPE_STRING,
+          "description", G_TYPE_STRING, "type name of the pad",
+          "flags", G_TYPE_STRING, "",  /* TODO: use gflags */
+          NULL),
+      "is-ghostpad", GST_TYPE_STRUCTURE, gst_structure_new ("value",
+          "type", G_TYPE_GTYPE, G_TYPE_BOOLEAN,
+          "description", G_TYPE_STRING, "is pad a ghostpad",
+          NULL),
+      "pad-direction", GST_TYPE_STRUCTURE, gst_structure_new ("value",
+          "type", G_TYPE_GTYPE, GST_TYPE_PAD_DIRECTION,
+          "description", G_TYPE_STRING, "ipad direction",
+          NULL),
+      NULL));
   /* *INDENT-ON* */
 }
 
index 07ad657..560b5b1 100644 (file)
@@ -139,6 +139,7 @@ check_PROGRAMS =                            \
        gst/gstclock                            \
        gst/gststructure                        \
        gst/gsttag                              \
+       gst/gsttracerrecord                             \
        gst/gsttagsetter                        \
        gst/gsttask                             \
        gst/gsttoc                              \
@@ -206,6 +207,8 @@ gst_gstcpp_SOURCES = gst/gstcpp.cc
 
 libs_gstlibscpp_SOURCES = libs/gstlibscpp.cc
 
+gst_gsttracerrecord_CFLAGS = $(GST_OBJ_CFLAGS) $(AM_CFLAGS) -DGST_USE_UNSTABLE_API
+
 gst_gstutils_LDADD = $(LDADD) $(GSL_LIBS) $(GMP_LIBS)
 
 gst_gstprintf_LDADD = \
index fcea84e..623abee 100644 (file)
@@ -44,6 +44,7 @@ gsttag
 gsttagsetter
 gsttoc
 gsttocsetter
+gsttracerrecord
 gsturi
 gstutils
 gstvalue
diff --git a/tests/check/gst/gsttracerrecord.c b/tests/check/gst/gsttracerrecord.c
new file mode 100644 (file)
index 0000000..f786fd9
--- /dev/null
@@ -0,0 +1,165 @@
+/* GStreamer
+ *
+ * Unit tests for GstTracerRecord
+ *
+ * Copyright (C) 2016 Stefan Sauer <ensonic@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/gstcheck.h>
+#include <gst/gsttracerrecord.h>
+
+static GList *messages;         /* NULL */
+static gboolean save_messages;  /* FALSE */
+
+static void
+tracer_log_func (GstDebugCategory * category,
+    GstDebugLevel level, const gchar * file, const gchar * function,
+    gint line, GObject * object, GstDebugMessage * message, gpointer unused)
+{
+  const gchar *dbg_msg;
+
+  if (!save_messages || level != GST_LEVEL_TRACE ||
+      !g_str_equal (category->name, "GST_TRACER")) {
+    return;
+  }
+
+  dbg_msg = gst_debug_message_get (message);
+  fail_unless (dbg_msg != NULL);
+
+  messages = g_list_append (messages, g_strdup (dbg_msg));
+}
+
+static void
+setup (void)
+{
+  gst_debug_remove_log_function (gst_debug_log_default);
+  gst_debug_add_log_function (tracer_log_func, NULL, NULL);
+  gst_debug_set_threshold_for_name ("GST_TRACER", GST_LEVEL_TRACE);
+  messages = NULL;
+  save_messages = FALSE;
+}
+
+static void
+cleanup (void)
+{
+  save_messages = FALSE;
+  gst_debug_set_threshold_for_name ("GST_TRACER", GST_LEVEL_NONE);
+  gst_debug_add_log_function (gst_debug_log_default, NULL, NULL);
+  gst_debug_remove_log_function (tracer_log_func);
+  g_list_foreach (messages, (GFunc) g_free, NULL);
+  messages = NULL;
+}
+
+
+GST_START_TEST (serialize_message_logging)
+{
+  GstTracerRecord *tr;
+  gchar *str;
+
+  /* *INDENT-OFF* */
+  tr = gst_tracer_record_new (gst_structure_new ("test.class",
+      "string", GST_TYPE_STRUCTURE, gst_structure_new ("value",
+          "type", G_TYPE_GTYPE, G_TYPE_STRING,
+          NULL),
+      NULL));
+  /* *INDENT-ON* */
+
+  save_messages = TRUE;
+  gst_tracer_record_log (tr, "test");
+  save_messages = FALSE;
+
+  fail_unless_equals_int (g_list_length (messages), 1);
+  str = (gchar *) messages->data;
+  fail_unless (str != NULL);
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (serialize_static_record)
+{
+  GstTracerRecord *tr;
+  GstStructure *s;
+  gchar *str;
+  gchar *str_val;
+  gint int_val;
+  gboolean bool_val;
+  GstPadDirection enum_val;
+
+  /* *INDENT-OFF* */
+  tr = gst_tracer_record_new (gst_structure_new ("test.class",
+      "string", GST_TYPE_STRUCTURE, gst_structure_new ("value",
+          "type", G_TYPE_GTYPE, G_TYPE_STRING,
+          NULL),
+      "int", GST_TYPE_STRUCTURE, gst_structure_new ("value",
+          "type", G_TYPE_GTYPE, G_TYPE_INT,
+          NULL),
+      "bool", GST_TYPE_STRUCTURE, gst_structure_new ("value",
+          "type", G_TYPE_GTYPE, G_TYPE_BOOLEAN,
+          NULL),
+      "enum", GST_TYPE_STRUCTURE, gst_structure_new ("value",
+          "type", G_TYPE_GTYPE, GST_TYPE_PAD_DIRECTION,
+          NULL),
+      NULL));
+  /* *INDENT-ON* */
+
+  save_messages = TRUE;
+  gst_tracer_record_log (tr, "test", 1, TRUE, GST_PAD_SRC);
+  save_messages = FALSE;
+
+  str = (gchar *) messages->data;
+  GST_INFO ("serialized to '%s'", str);
+
+  s = gst_structure_from_string (str, NULL);
+  fail_unless (s != NULL);
+
+  fail_unless_equals_string (gst_structure_get_name (s), "test");
+
+  fail_unless (gst_structure_get (s,
+          "string", G_TYPE_STRING, &str_val,
+          "int", G_TYPE_INT, &int_val,
+          "bool", G_TYPE_BOOLEAN, &bool_val,
+          "enum", GST_TYPE_PAD_DIRECTION, &enum_val, NULL));
+  fail_unless_equals_int (int_val, 1);
+  fail_unless_equals_string (str_val, "test");
+  fail_unless_equals_int (bool_val, TRUE);
+  fail_unless_equals_int (enum_val, GST_PAD_SRC);
+
+  gst_structure_free (s);
+}
+
+GST_END_TEST;
+
+
+static Suite *
+gst_tracer_record_suite (void)
+{
+  Suite *s = suite_create ("GstTracerRecord");
+  TCase *tc_chain = tcase_create ("record");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_checked_fixture (tc_chain, setup, cleanup);
+  tcase_add_test (tc_chain, serialize_message_logging);
+  tcase_add_test (tc_chain, serialize_static_record);
+
+  /* FIXME: add more tests, e.g. enums, pointer types and optional fields */
+
+  return s;
+}
+
+GST_CHECK_MAIN (gst_tracer_record);
index 7179df5..860306d 100644 (file)
@@ -1391,7 +1391,9 @@ EXPORTS
        gst_tracer_factory_get_list
        gst_tracer_factory_get_type
        gst_tracer_get_type
-       gst_tracer_log_trace
+       gst_tracer_record_get_type
+       gst_tracer_record_log
+       gst_tracer_record_new
        gst_tracer_register
        gst_tracing_register_hook
        gst_type_find_factory_call_function