static void cockpit_metrics_close (CockpitChannel *channel, const gchar *problem) { CockpitMetrics *self = COCKPIT_METRICS (channel); if (self->priv->timeout) { g_source_remove (self->priv->timeout); self->priv->timeout = 0; } COCKPIT_CHANNEL_CLASS (cockpit_metrics_parent_class)->close (channel, problem); }
static void cockpit_metrics_dispose (GObject *object) { CockpitMetrics *self = COCKPIT_METRICS (object); if (self->priv->timeout) { g_source_remove (self->priv->timeout); self->priv->timeout = 0; } if (self->priv->last_meta) { json_object_unref (self->priv->last_meta); self->priv->last_meta = NULL; } if (self->priv->last_data) { g_free (self->priv->last_data[0]); g_free (self->priv->last_data); self->priv->last_data = NULL; } if (self->priv->next_meta) { json_object_unref (self->priv->next_meta); self->priv->next_meta = NULL; } if (self->priv->next_data) { g_free (self->priv->next_data[0]); g_free (self->priv->next_data); self->priv->next_data = NULL; } if (self->priv->derived) { g_free (self->priv->derived[0]); g_free (self->priv->derived); self->priv->derived = NULL; } g_free (self->priv->metric_info); self->priv->metric_info = NULL; G_OBJECT_CLASS (cockpit_metrics_parent_class)->dispose (object); }
static void cockpit_internal_metrics_prepare (CockpitChannel *channel) { CockpitInternalMetrics *self = COCKPIT_INTERNAL_METRICS (channel); JsonObject *options; JsonArray *metrics; int i; COCKPIT_CHANNEL_CLASS (cockpit_internal_metrics_parent_class)->prepare (channel); options = cockpit_channel_get_options (channel); /* "instances" option */ if (!cockpit_json_get_strv (options, "instances", NULL, (gchar ***)&self->instances)) { cockpit_channel_fail (channel, "protocol-error", "invalid \"instances\" option (not an array of strings)"); return; } /* "omit-instances" option */ if (!cockpit_json_get_strv (options, "omit-instances", NULL, (gchar ***)&self->omit_instances)) { cockpit_channel_fail (channel, "protocol-error", "invalid \"omit-instances\" option (not an array of strings)"); return; } /* "metrics" option */ self->n_metrics = 0; if (!cockpit_json_get_array (options, "metrics", NULL, &metrics)) { cockpit_channel_fail (channel, "protocol-error", "invalid \"metrics\" option was specified (not an array)"); return; } if (metrics) self->n_metrics = json_array_get_length (metrics); self->metrics = g_new0 (MetricInfo, self->n_metrics); for (i = 0; i < self->n_metrics; i++) { MetricInfo *info = &self->metrics[i]; if (!convert_metric_description (self, json_array_get_element (metrics, i), info, i)) return; if (!info->desc) { cockpit_channel_close (channel, "not-supported"); return; } } /* "interval" option */ if (!cockpit_json_get_int (options, "interval", 1000, &self->interval)) { cockpit_channel_fail (channel, "protocol-error", "invalid \"interval\" option"); return; } else if (self->interval <= 0 || self->interval > G_MAXINT) { cockpit_channel_fail (channel, "protocol-error", "invalid \"interval\" value: %" G_GINT64_FORMAT, self->interval); return; } self->need_meta = TRUE; cockpit_metrics_metronome (COCKPIT_METRICS (self), self->interval); cockpit_channel_ready (channel, NULL); }
static void cockpit_internal_metrics_tick (CockpitMetrics *metrics, gint64 timestamp) { CockpitInternalMetrics *self = (CockpitInternalMetrics *)metrics; struct timeval now_timeval; gint64 now; gettimeofday (&now_timeval, NULL); now = timestamp_from_timeval (&now_timeval); /* Reset samples */ for (int i = 0; i < self->n_metrics; i++) { MetricInfo *info = &self->metrics[i]; if (info->desc->instanced) g_hash_table_foreach (info->instances, instance_reset, NULL); else info->value = NAN; } /* Sample */ if (self->samplers & CPU_SAMPLER) cockpit_cpu_samples (COCKPIT_SAMPLES (self)); if (self->samplers & MEMORY_SAMPLER) cockpit_memory_samples (COCKPIT_SAMPLES (self)); if (self->samplers & BLOCK_SAMPLER) cockpit_block_samples (COCKPIT_SAMPLES (self)); if (self->samplers & NETWORK_SAMPLER) cockpit_network_samples (COCKPIT_SAMPLES (self)); if (self->samplers & MOUNT_SAMPLER) cockpit_mount_samples (COCKPIT_SAMPLES (self)); if (self->samplers & CGROUP_SAMPLER) cockpit_cgroup_samples (COCKPIT_SAMPLES (self)); if (self->samplers & DISK_SAMPLER) cockpit_disk_samples (COCKPIT_SAMPLES (self)); /* Check for disappeared instances */ for (int i = 0; i < self->n_metrics; i++) { MetricInfo *info = &self->metrics[i]; if (info->desc->instanced) if (g_hash_table_foreach_remove (info->instances, instance_unseen, NULL) > 0) self->need_meta = TRUE; } /* Send a meta message if necessary. This will also allocate a new buffer and setup the instance indices. */ if (self->need_meta) { send_meta (self); self->need_meta = FALSE; } /* Ship them out */ double **buffer = cockpit_metrics_get_data_buffer (COCKPIT_METRICS (self)); for (int i = 0; i < self->n_metrics; i++) { MetricInfo *info = &self->metrics[i]; if (info->desc->instanced) { GHashTableIter iter; gpointer key, value; g_hash_table_iter_init (&iter, info->instances); while (g_hash_table_iter_next (&iter, &key, &value)) { InstanceInfo *inst = value; buffer[i][inst->index] = inst->value; } } else buffer[i][0] = info->value; } cockpit_metrics_send_data (COCKPIT_METRICS (self), now); cockpit_metrics_flush_data (COCKPIT_METRICS (self)); }
static void send_meta (CockpitInternalMetrics *self) { JsonArray *metrics; JsonObject *metric; JsonObject *root; struct timeval now_timeval; gint64 now; gettimeofday (&now_timeval, NULL); now = timestamp_from_timeval (&now_timeval); root = json_object_new (); json_object_set_int_member (root, "timestamp", now); json_object_set_int_member (root, "now", now); json_object_set_int_member (root, "interval", self->interval); metrics = json_array_new (); for (int i = 0; i < self->n_metrics; i++) { MetricInfo *info = &self->metrics[i]; metric = json_object_new (); /* Name and derivation mode */ json_object_set_string_member (metric, "name", info->desc->name); if (info->derive) json_object_set_string_member (metric, "derive", info->derive); /* Instances */ if (info->desc->instanced) { GHashTableIter iter; gpointer key, value; int index; JsonArray *instances = json_array_new (); g_hash_table_iter_init (&iter, info->instances); index = 0; while (g_hash_table_iter_next (&iter, &key, &value)) { const gchar *name = key; InstanceInfo *inst = value; /* HACK: We can't use json_builder_add_string_value here since it turns empty strings into 'null' values inside arrays. https://bugzilla.gnome.org/show_bug.cgi?id=730803 */ { JsonNode *string_element = json_node_alloc (); json_node_init_string (string_element, name); json_array_add_element (instances, string_element); } inst->index = index++; } json_object_set_array_member (metric, "instances", instances); } /* Units and semantics */ json_object_set_string_member (metric, "units", info->desc->units); json_object_set_string_member (metric, "semantics", info->desc->semantics); json_array_add_object_element (metrics, metric); } json_object_set_array_member (root, "metrics", metrics); cockpit_metrics_send_meta (COCKPIT_METRICS (self), root, FALSE); json_object_unref (root); }