You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by GitBox <gi...@apache.org> on 2018/08/09 14:15:07 UTC
[GitHub] andrzej-kaczmarek closed pull request #873: [WIP] sys/metrics: Add
framework for logging events data
andrzej-kaczmarek closed pull request #873: [WIP] sys/metrics: Add framework for logging events data
URL: https://github.com/apache/mynewt-core/pull/873
This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:
As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):
diff --git a/apps/metrics/pkg.yml b/apps/metrics/pkg.yml
new file mode 100644
index 0000000000..c1445ad87a
--- /dev/null
+++ b/apps/metrics/pkg.yml
@@ -0,0 +1,29 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+pkg.name: apps/metrics
+pkg.type: app
+pkg.description:
+pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+
+pkg.deps:
+ - kernel/os
+ - sys/console/full
+ - sys/metrics
+ - sys/sysinit
diff --git a/apps/metrics/src/main.c b/apps/metrics/src/main.c
new file mode 100755
index 0000000000..b5f9671a79
--- /dev/null
+++ b/apps/metrics/src/main.c
@@ -0,0 +1,156 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include "os/os.h"
+#include "sysinit/sysinit.h"
+#include "metrics/metrics.h"
+#include "tinycbor/cbor_mbuf_reader.h"
+#include "tinycbor/cbor.h"
+#include "log/log.h"
+#include "sysflash/sysflash.h"
+#include "fcb/fcb.h"
+
+/*
+ * XXX
+ * Metrics are numbered starting from 0 in order as defined. It may be good idea
+ * to define an enum with proper symbols to identify each metric so it's easy
+ * to rearrange them later. Or we may find some nice way to actually define
+ * these symbols automatically, not yet sure how though...
+ */
+
+/* Define symbols for metrics */
+enum {
+ MY_METRIC_VAL_S,
+ MY_METRIC_VAL_U,
+ MY_METRIC_VAL_SS16,
+ MY_METRIC_VAL_SU32,
+ MY_METRIC_VAL_SS32,
+};
+
+/* Define all metrics */
+METRICS_SECT_START(my_metrics)
+ METRICS_SECT_ENTRY(val_s, METRICS_TYPE_SINGLE_S)
+ METRICS_SECT_ENTRY(val_u, METRICS_TYPE_SINGLE_U)
+ METRICS_SECT_ENTRY(val_ss16, METRICS_TYPE_SERIES_S16)
+ METRICS_SECT_ENTRY(val_su32, METRICS_TYPE_SERIES_U32)
+ METRICS_SECT_ENTRY(val_ss32, METRICS_TYPE_SERIES_S32)
+METRICS_SECT_END;
+
+/* Declare event struct to accommodate all metrics */
+METRICS_EVENT_DECLARE(my_event, my_metrics);
+
+/* Sample event */
+struct my_event g_event;
+
+/* Target log instance */
+static struct log g_log;
+static struct fcb_log g_log_fcb;
+static struct flash_area g_log_fcb_fa;
+
+static void
+init_log_instance(void)
+{
+ const struct flash_area *fa;
+ int rc;
+
+ /* Temporarily just use reboot log fa */
+ rc = flash_area_open(FLASH_AREA_REBOOT_LOG, &fa);
+ assert(rc == 0);
+
+ g_log_fcb_fa = *fa;
+ g_log_fcb.fl_fcb.f_sectors = &g_log_fcb_fa;
+ g_log_fcb.fl_fcb.f_sector_cnt = 1;
+ g_log_fcb.fl_fcb.f_magic = 0xBABABABA;
+ g_log_fcb.fl_fcb.f_version = g_log_info.li_version;
+
+ g_log_fcb.fl_entries = 0;
+
+ rc = fcb_init(&g_log_fcb.fl_fcb);
+ if (rc) {
+ flash_area_erase(fa, 0, fa->fa_size);
+ rc = fcb_init(&g_log_fcb.fl_fcb);
+ assert(rc == 0);
+ }
+
+ log_register("my_metrics", &g_log, &log_fcb_handler, &g_log_fcb,
+ LOG_SYSLEVEL);
+}
+
+int
+main(void)
+{
+ struct os_mbuf *om;
+ int i;
+
+ sysinit();
+
+ init_log_instance();
+
+ /* Initialize event internals and enable logging for all metrics */
+ metrics_event_init(&g_event.hdr, my_metrics, METRICS_SECT_COUNT(my_metrics), "myev");
+ metrics_event_register(&g_event.hdr);
+ metrics_set_state_mask(&g_event.hdr, 0xffffffff);
+
+ /* Start new event */
+ metrics_event_start(&g_event.hdr, os_cputime_get32());
+
+ /* Log some data to event */
+ metrics_set_value(&g_event.hdr, MY_METRIC_VAL_S, -10);
+ metrics_set_value(&g_event.hdr, MY_METRIC_VAL_U, 10);
+ metrics_set_value(&g_event.hdr, MY_METRIC_VAL_SU32, 100);
+ metrics_set_value(&g_event.hdr, MY_METRIC_VAL_SU32, 101);
+ metrics_set_value(&g_event.hdr, MY_METRIC_VAL_SU32, 102);
+ metrics_set_value(&g_event.hdr, MY_METRIC_VAL_SU32, 103);
+
+ /* Serialize event to mbuf from metrics pool */
+ om = metrics_get_mbuf();
+ metrics_event_to_cbor(&g_event.hdr, om);
+ os_mbuf_free_chain(om);
+
+ /* Start new event */
+ metrics_event_start(&g_event.hdr, os_cputime_get32());
+ metrics_event_set_log(&g_event.hdr, &g_log, LOG_MODULE_DEFAULT, LOG_LEVEL_INFO);
+
+ /* Log some data to event */
+ metrics_set_value(&g_event.hdr, MY_METRIC_VAL_S, -10);
+ metrics_set_value(&g_event.hdr, MY_METRIC_VAL_U, 10);
+ metrics_set_value(&g_event.hdr, MY_METRIC_VAL_U, 11);
+ metrics_set_value(&g_event.hdr, MY_METRIC_VAL_U, 12);
+ for (i = 32750; i < 32800; i++) {
+ metrics_set_value(&g_event.hdr, MY_METRIC_VAL_SS16, -i);
+ metrics_set_value(&g_event.hdr, MY_METRIC_VAL_SS32, -i);
+ }
+
+ /*
+ * event state can be dumped via shell:
+ * select metrics
+ * list-events 1
+ * event-dump myev
+ */
+
+ while (1) {
+ os_eventq_run(os_eventq_dflt_get());
+ }
+
+ return 0;
+}
diff --git a/apps/metrics/syscfg.yml b/apps/metrics/syscfg.yml
new file mode 100644
index 0000000000..180753b60d
--- /dev/null
+++ b/apps/metrics/syscfg.yml
@@ -0,0 +1,24 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+syscfg.vals:
+ LOG_FCB: 1
+ LOG_CLI: 1
+ LOG_VERSION: 3
+ METRICS_CLI: 1
diff --git a/sys/metrics/include/metrics/metrics.h b/sys/metrics/include/metrics/metrics.h
new file mode 100644
index 0000000000..e2d10a8118
--- /dev/null
+++ b/sys/metrics/include/metrics/metrics.h
@@ -0,0 +1,434 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef __SYS_METRICS_H__
+#define __SYS_METRICS_H__
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "log/log.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Event metrics is a generic API to collect various data about events happening
+ * in a system.
+ *
+ * Events are defined by application and can represent a simple notification
+ * (e.g. "battery state") as well as complex event with data collected over time
+ * (e.g. "Bluetooth connection event") - there are no constraints here.
+ *
+ * Each event has number of metrics associated with it. These metrics are
+ * properties of an event and each event can have up to 32 metrics defined.
+ * Each metric is either a single value (only one value can be stored per event)
+ * or a series value (multiple values can be stored per event). For example:
+ *
+ * Simple "battery state" event may define metrics:
+ * - battery type (single value)
+ * - battery level (single value)
+ *
+ * Bluetooth connection event is series of packets exchanged over the air during
+ * connection thus "Bluetooth connection event" may define following metrics:
+ * - connection handle (single value)
+ * - connection PHY (single value)
+ * - packet type (series value, one value for each packet)
+ * - inter-frame space (series value)
+ * - packet count (single value)
+ *
+ * There is no limit on number of events created in system (except for available
+ * memory).
+ *
+ * To use events, first a set of metrics needs to be defined using helper macros
+ * as below:
+ *
+ * METRICS_SECT_START(my_power_metrics)
+ * METRICS_SECT_ENTRY(event_src, EVENT_METRIC_TYPE_SINGLE_U)
+ * METRICS_SECT_ENTRY(power_per_sec, EVENT_METRIC_TYPE_SERIES_U16)
+ * METRICS_SECT_ENTRY(avg_power, EVENT_METRIC_TYPE_SINGLE_U)
+ * METRICS_SECT_ENTRY(min_power, EVENT_METRIC_TYPE_SINGLE_U)
+ * METRICS_SECT_ENTRY(max_power, EVENT_METRIC_TYPE_SINGLE_U)
+ * METRICS_SECT_END
+ *
+ * This creates metrics section named 'my_power_metrics' with 4 metrics inside,
+ * each has name and value type specified. Single value metrics store only last
+ * value logged. Series value metrics store all logged values.
+ *
+ * NOTE:
+ * Currently APIs identify metrics by their ordinal number in definition, i.e.:
+ * event_src => 0, power_per_sec => 1, ...
+ * To workaround this some symbols may be defined manually, e.g. using an enum:
+ * enum {
+ * POWER_METRIC_EVENT_SRC, // 0
+ * POWER_METRIC_PPS, // 1
+ * POWER_METRIC_AVG, // 2
+ * POWER_METRIC_MIN, // 3
+ * POWER_METRIC_MAX, // 4
+ * };
+ *
+ * Next step is to define a structure which describes an event that can store
+ * data for all metrics:
+ *
+ * METRICS_EVENT_DECLARE(power_event, my_power_metrics);
+ *
+ * This defines new type 'struct power_source_event' which is a structure large
+ * enough to hold data for all metrics defined in set 'my_power_metrics'. Such
+ * type can be used to define event variable which is an event instance (can be
+ * either static variable or dynamically allocated - it does not matter), e.g.:
+ *
+ * struct power_event my_power_event;
+ *
+ * Event variable needs to be initialized before usage. Each event struct has
+ * `hdr` field included which should be passed as an argument identifying event
+ * in APIs. Metrics set passed to initialization function shall be the same as
+ * used to define event struct.
+ *
+ * metrics_event_init(&my_power_event.hdr, my_power_metrics,
+ * METRICS_SECT_COUNT(my_metrics), "power_event");
+ *
+ * Event data may be logged manually (e.g. serialized to CBOR using appropriate
+ * APIs) or automatically logged to log instance:
+ *
+ * struct log log; // see logging subsystem on how to handle this
+ * event_metric_set_log(&log, LOG_MODULE_DEFAULT, LOG_LEVEL_INFO);
+ *
+ * Sample scenario for collecting data to event might look as below:
+ *
+ * 1. start event with current timestamp
+ * metrics_event_start(&my_power_event.hdr, os_cputime_get32());
+ *
+ * 2. log some starting value relavant to this event, e.g. what triggered event
+ * metrics_set_value(&my_power_event.hdr, POWER_METRIC_EVENT_SRC, xxx);
+ *
+ * 3. log current power value every second
+ * metrics_set_value(&my_power_event.hdr, POWER_METRIC_PPS, cur_power);
+ *
+ * 4. at end of event log calculated min/max/avg values
+ * metrics_set_value(&my_power_event.hdr, POWER_METRIC_AVG, power_avg);
+ * metrics_set_value(&my_power_event.hdr, POWER_METRIC_MIN, power_min);
+ * metrics_set_value(&my_power_event.hdr, POWER_METRIC_MAX, power_max);
+ *
+ * 5. finish collecting data for this event
+ * metrics_event_end(&my_power_event.hdr);
+ *
+ * Now the data can be collected for the same event again by repeating these
+ * steps. In case data collection starts just after finishing an event, the
+ * call to metrics_event_end() may be omitted as metrics_event_start() will do
+ * this implicitly.
+ *
+ * The amount of data which can be collected for all data series of all metrics
+ * in a system is limited by capacity of mempool defined by following syscfg:
+ * METRICS_POOL_COUNT - number of blocks in mempool
+ * METRICS_POOL_SIZE - size of each block in mempool
+ *
+ * In general, each series require at least single block to hold a single value.
+ * As number of values increases in a series it may be necessary to allocate
+ * more blocks for the same data series. Once event data is reset, all blocks
+ * allocated for an event are freed.
+ */
+
+/* Helper to define metric type - use types defined below instead! */
+#define METRICS_TYPE(__series, __sign, __size) \
+ ((__series) << 7) | ((__sign) << 6) | ((__size))
+
+/* Type definitions for metrics */
+#define METRICS_TYPE_SINGLE_U METRICS_TYPE(0, 0, sizeof(uint32_t))
+#define METRICS_TYPE_SINGLE_S METRICS_TYPE(0, 1, sizeof(uint32_t))
+#define METRICS_TYPE_SERIES_U8 METRICS_TYPE(1, 0, sizeof(uint8_t))
+#define METRICS_TYPE_SERIES_U16 METRICS_TYPE(1, 0, sizeof(uint16_t))
+#define METRICS_TYPE_SERIES_U32 METRICS_TYPE(1, 0, sizeof(uint32_t))
+#define METRICS_TYPE_SERIES_S8 METRICS_TYPE(1, 1, sizeof(uint8_t))
+#define METRICS_TYPE_SERIES_S16 METRICS_TYPE(1, 1, sizeof(uint16_t))
+#define METRICS_TYPE_SERIES_S32 METRICS_TYPE(1, 1, sizeof(uint32_t))
+#define METRICS_TYPE_SINGLE (METRICS_TYPE_SINGLE_U)
+#define METRICS_TYPE_SERIES (METRICS_TYPE_SERIES_U32)
+
+/* Metric definition - use METRICS_SECT_* helpers to create */
+struct metrics_metric_def {
+ const char *name;
+ uint8_t type;
+};
+
+/* Event header - use EVENT_DECLARE() helpers to create */
+struct metrics_event_hdr {
+ const char *name;
+ struct log *log;
+ int log_module;
+ int log_level;
+ uint32_t timestamp;
+ uint32_t enabled;
+ uint32_t set;
+ uint8_t count;
+ STAILQ_ENTRY(metrics_event_hdr) next;
+ const struct metrics_metric_def *defs;
+};
+
+/*
+ * Helpers to define metrics section
+ *
+ * Metrics section defines set of metrics which can be used by an event.
+ */
+#define METRICS_SECT_START(_metrics) \
+ static const struct metrics_metric_def _metrics[] = {
+#define METRICS_SECT_ENTRY(_name, _type) \
+ { .name = #_name, .type = _type },
+#define METRICS_SECT_END \
+ }
+
+/**
+ * Helper to count number of defined metrics in section
+ *
+ * @param _metrics Name of metrics section
+ */
+#define METRICS_SECT_COUNT(_metrics) \
+ sizeof(_metrics) / sizeof(_metrics[0])
+
+/**
+ * Helper to declare struct type for event definition
+ *
+ * This macro should be used to declare a named struct type which can hold event
+ * data for specified metrics. New struct type can be then used to create event
+ * variable. Each struct has `hdr` field which shall be passed to other APIs
+ * wherever event needs to be passed.
+ *
+ * @param _event Event structure type name
+ * @param _metrics Metrics definitions (metrics section name)
+ */
+#define METRICS_EVENT_DECLARE(_event, _metrics) \
+ struct _event { \
+ struct metrics_event_hdr hdr; \
+ uintptr_t vals[ METRICS_SECT_COUNT(_metrics) ]; \
+ };
+
+/**
+ * Initialize event
+ *
+ * This shall be called to initialize each event variable before it can be used
+ * with other macros.
+ *
+ * @param hdr Event header
+ * @param metrics Metrics definitions (metrics section name)
+ * @param count Number of metrics definition
+ * @param name Printable event name
+ *
+ * @return 0 on success, negative value otherwise
+ */
+int metrics_event_init(struct metrics_event_hdr *hdr,
+ const struct metrics_metric_def *metrics, uint8_t count,
+ const char *name);
+
+/**
+ * Register event
+ *
+ * This can be used to register event in system. It is optional to register an
+ * event, however only registered events can be accessed via e.g. shell.
+ *
+ * @param hdr Event header
+ *
+ * @return 0 on success, negative value otherwise
+ */
+int metrics_event_register(struct metrics_event_hdr *hdr);
+
+/**
+ * Set log instance for an event
+ *
+ * Set log instance for existing event. Data collected in an event are
+ * automatically sent to this log instance when even is done. Log entry is
+ * created with specified module and level.
+ *
+ * @param hdr Event header
+ * @param log Log instance
+ * @param module Log module
+ * @param level Log level
+ *
+ * @return 0 on success, negative value otherwise
+ *
+ * @sa log_append
+ */
+int metrics_event_set_log(struct metrics_event_hdr *hdr, struct log *log,
+ int module, int level);
+
+/**
+ * Start new event
+ *
+ * Start collecting new data for an event. Any data previously collected in this
+ * event are first logged (if log instance is set) and then reset.
+ *
+ * @param hdr Event header
+ * @param timestamp Event timestamp
+ *
+ * @return 0 on success, negative value otherwise
+ */
+int metrics_event_start(struct metrics_event_hdr *hdr, uint32_t timestamp);
+
+/**
+ * End an event
+ *
+ * End an event by logging collected data to log instance (if log instance is
+ * set) and then reset all data. This is also done automatically when event is
+ * started and there are data collected already, i.e. there was not explicit
+ * call to event_metric_end().
+ *
+ * @param hdr Event header
+ *
+ * @return 0 on success, negative value otherwise
+ */
+int metrics_event_end(struct metrics_event_hdr *hdr);
+
+/**
+ * Set metric data collection state
+ *
+ * This can be used to enable or disable data collection for given metric. When
+ * data collection for metric is disabled, any subsequent data for this metric
+ * are ignored. If disabled metric already has some data collected, these data
+ * remain unaffected.
+ *
+ * @param hdr Event header
+ * @param metric Metric identifier
+ * @param state New state for metric data collection
+ *
+ * @return 0 on success, negative value otherwise
+ */
+int metrics_set_state(struct metrics_event_hdr *hdr, uint8_t metric,
+ bool state);
+
+/**
+ * Enable metric data collection state
+ *
+ * This can be used to enable data collection for multiple metrics at once.
+ * Affected metrics are specified by bitmask where each bit number corresponds
+ * to metric identifier.
+ *
+ * @param hdr Event header
+ * @param mask Metrics bitmask
+ *
+ * @return 0 on success, negative value otherwise
+ */
+int metrics_set_state_mask(struct metrics_event_hdr *hdr, uint32_t mask);
+
+/**
+ * Disable metric data collection state
+ *
+ * This can be used to disable data collection for multiple metrics at once.
+ * Affected metrics are specified by bitmask where each bit number corresponds
+ * to metric identifier.
+ *
+ * @param hdr Event header
+ * @param mask Metrics bitmask
+ *
+ * @return 0 on success, negative value otherwise
+ */
+int metrics_clr_state_mask(struct metrics_event_hdr *hdr, uint32_t mask);
+/**
+ * Get metric data collection state
+ *
+ * Returns current state of metrics collection state as set by
+ * metrics_set_state_mask() and metrics_clr_state_mask().
+ *
+ * @param hdr Event header
+ *
+ * @return metrics bitmask
+ */
+uint32_t metrics_get_state_mask(struct metrics_event_hdr *hdr);
+
+/**
+ * Set metric value
+ *
+ * This can be used to set new value for a metric in an event.
+ * Depending on metric type, new value either overwrites current value or is
+ * appended to existing values in series.
+ * Value can be truncated if is outside of range for specified metric type.
+ *
+ * @param hdr Event header
+ * @param metric Metric identifier
+ * @param val Metric value
+ *
+ * @return 0 on success, negative value otherwise
+ */
+int metrics_set_value(struct metrics_event_hdr *hdr, uint8_t metric,
+ uint32_t val);
+
+/**
+ * Set metric value
+ *
+ * This can be used to set new value for a metric in an event.
+ * Metric type shall be 'single', otherwise this function fails.
+ *
+ * @param hdr Event header
+ * @param metric Metric identifier
+ * @param val Metric value
+ *
+ * @return 0 on success, negative value otherwise
+ */
+int metrics_set_single_value(struct metrics_event_hdr *hdr, uint8_t metric,
+ uint32_t val);
+
+/**
+ * Set metric value
+ *
+ * This can be used to set new value for a metric in an event.
+ * Metric type shall be 'series', otherwise this function fails.
+ * Value can be truncated if is outside of range for specified metric type.
+ *
+ * @param hdr Event header
+ * @param metric Metric identifier
+ * @param val Metric value
+ *
+ * @return 0 on success, negative value otherwise
+ */
+int metrics_set_series_value(struct metrics_event_hdr *hdr, uint8_t metric,
+ uint32_t val);
+
+/**
+ * Serialize event data to CBOR
+ *
+ * Serialize event data to os_mbuf using CBOR format. Only currently enabled
+ * metrics will be included in output. Metrics which do not have data set will
+ * have value set to 'undefined'.
+ *
+ * Data collected in an event remain unaffected. The only exception is when
+ * destination mbuf is allocated using event_metric_get_mbuf() - data are then
+ * removed from event during serialization to reduce memory usage and free space
+ * for CBOR stream. This way of calling should thus be used only if all data for
+ * an event were already collected.
+ *
+ * @param hdr Event header
+ * @param om Target mbuf
+ *
+ * @return 0 on success, negative value otherwise
+ */
+int metrics_event_to_cbor(struct metrics_event_hdr *hdr, struct os_mbuf *om);
+
+/**
+ * Get mbuf from metrics internal pool
+ *
+ * Internal pool can be used when serializing data to CBOR format to reduce
+ * memory usage since pool is then shared between event and CBOR stream. See
+ * event_metric_to_cbor() for details.
+ *
+ * @return mbuf
+ */
+struct os_mbuf *metrics_get_mbuf(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __SYS_METRICS_H__ */
diff --git a/sys/metrics/pkg.yml b/sys/metrics/pkg.yml
new file mode 100644
index 0000000000..759c107cf9
--- /dev/null
+++ b/sys/metrics/pkg.yml
@@ -0,0 +1,37 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+pkg.name: sys/metrics
+pkg.description: Events logging framework
+pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+ - metrics
+
+pkg.deps:
+ - kernel/os
+ - sys/log/full
+ - encoding/tinycbor
+pkg.apis:
+ - metrics
+pkg.deps.METRICS_CLI:
+ - sys/shell
+
+pkg.init:
+ metrics_pkg_init: 500
diff --git a/sys/metrics/src/cli.c b/sys/metrics/src/cli.c
new file mode 100644
index 0000000000..f32e62fdb4
--- /dev/null
+++ b/sys/metrics/src/cli.c
@@ -0,0 +1,260 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include "os/os.h"
+#include "shell/shell.h"
+#include "console/console.h"
+#include "metrics/metrics.h"
+#include "tinycbor/cbor.h"
+#include "tinycbor/cbor_mbuf_reader.h"
+
+static STAILQ_HEAD(, metrics_event_hdr) g_event_list =
+ STAILQ_HEAD_INITIALIZER(g_event_list);
+
+static struct metrics_event_hdr *
+find_event_by_name(const char *name)
+{
+ struct metrics_event_hdr *hdr;
+
+ STAILQ_FOREACH(hdr, &g_event_list, next) {
+ if (!strcmp(hdr->name, name)) {
+ break;
+ }
+ }
+
+ return hdr;
+}
+
+static int
+find_metric_by_name(struct metrics_event_hdr *hdr, const char *name)
+{
+ int i;
+
+ for (i = 0; i < hdr->count; i++) {
+ if (!strcmp(hdr->defs[i].name, name)) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+static const char *
+metric_type_str(uint8_t type)
+{
+ switch (type) {
+ case METRICS_TYPE_SINGLE_U:
+ return "unsigned";
+ case METRICS_TYPE_SINGLE_S:
+ return "signed";
+ case METRICS_TYPE_SERIES_U8:
+ return "unsigned8-series";
+ case METRICS_TYPE_SERIES_S8:
+ return "signed8-series";
+ case METRICS_TYPE_SERIES_U16:
+ return "unsigned16-series";
+ case METRICS_TYPE_SERIES_S16:
+ return "signed16-series";
+ case METRICS_TYPE_SERIES_U32:
+ return "unsigned32-series";
+ case METRICS_TYPE_SERIES_S32:
+ return "signed32-series";
+ }
+
+ return "<unknown>";
+}
+
+static void
+print_event_metrics(struct metrics_event_hdr *hdr)
+{
+ int i;
+
+ for (i = 0; i < hdr->count; i++) {
+ console_printf(" %d = %s (%s, %d)\n", i, hdr->defs[i].name,
+ metric_type_str(hdr->defs[i].type),
+ !!(hdr->enabled & (1 << i)));
+ }
+}
+
+static int
+cmd_list_events(int argc, char **argv)
+{
+ struct metrics_event_hdr *hdr;
+ bool full = false;
+
+ if (argc > 1) {
+ full = atoi(argv[1]);
+ }
+
+ STAILQ_FOREACH(hdr, &g_event_list, next) {
+ console_printf("%s\n", hdr->name);
+ if (full) {
+ print_event_metrics(hdr);
+ }
+ }
+
+ return 0;
+}
+
+static int
+cmd_list_event_metrics(int argc, char **argv)
+{
+ struct metrics_event_hdr *hdr;
+
+ if (argc < 2) {
+ console_printf("Event name not specified\n");
+ return -1;
+ }
+
+ STAILQ_FOREACH(hdr, &g_event_list, next) {
+ if (!strcmp(hdr->name, argv[1])) {
+ print_event_metrics(hdr);
+ return 0;
+ }
+ }
+
+ console_printf("Event '%s' not found\n", argv[1]);
+
+ return -1;
+}
+
+static int
+cmd_metric_set(int argc, char **argv)
+{
+ struct metrics_event_hdr *hdr;
+ int i;
+
+ if (argc < 4) {
+ console_printf("Event and/or metric name not specified\n");
+ return -1;
+ }
+
+ hdr = find_event_by_name(argv[1]);
+ if (!hdr) {
+ console_printf("Event '%s' not found\n", argv[1]);
+ return -1;
+ }
+
+ i = find_metric_by_name(hdr, argv[2]);
+ if (i < 0) {
+ console_printf("Metric '%s' not found\n", argv[2]);
+ return -1;
+ }
+
+ metrics_set_state(hdr, i, atoi(argv[3]));
+
+ return -1;
+}
+
+static int
+cmd_event_dump(int argc, char **argv)
+{
+ struct cbor_mbuf_reader reader;
+ struct CborParser parser;
+ struct CborValue value;
+ struct metrics_event_hdr *hdr;
+ struct os_mbuf *om;
+
+ if (argc < 2) {
+ console_printf("Event name not specified\n");
+ return -1;
+ }
+
+ hdr = find_event_by_name(argv[1]);
+ if (!hdr) {
+ console_printf("Event '%s' not found\n", argv[1]);
+ return -1;
+ }
+
+ /* We use msys so serializing event to CBOR will be non-destructive */
+ om = os_msys_get_pkthdr(50, 0);
+ metrics_event_to_cbor(hdr, om);
+ cbor_mbuf_reader_init(&reader, om, 0);
+ cbor_parser_init(&reader.r, 0, &parser, &value);
+ cbor_value_to_pretty(stdout, &value);
+ os_mbuf_free_chain(om);
+
+ console_printf("\n");
+
+ return 0;
+}
+
+static int
+cmd_event_end(int argc, char **argv)
+{
+ struct metrics_event_hdr *hdr;
+
+ if (argc < 2) {
+ console_printf("Event name not specified\n");
+ return -1;
+ }
+
+ hdr = find_event_by_name(argv[1]);
+ if (!hdr) {
+ console_printf("Event '%s' not found\n", argv[1]);
+ return -1;
+ }
+
+ metrics_event_end(hdr);
+
+ return 0;
+}
+
+static const struct shell_cmd metrics_commands[] = {
+ {
+ .sc_cmd = "list-events",
+ .sc_cmd_func = cmd_list_events,
+ },
+ {
+ .sc_cmd = "list-event-metrics",
+ .sc_cmd_func = cmd_list_event_metrics,
+ },
+ {
+ .sc_cmd = "metric-set",
+ .sc_cmd_func = cmd_metric_set,
+ },
+ {
+ .sc_cmd = "event-dump",
+ .sc_cmd_func = cmd_event_dump,
+ },
+ {
+ .sc_cmd = "event-end",
+ .sc_cmd_func = cmd_event_end,
+ },
+ { },
+};
+
+int
+metrics_cli_register_event(struct metrics_event_hdr *hdr)
+{
+ STAILQ_INSERT_TAIL(&g_event_list, hdr, next);
+
+ return 0;
+}
+
+int
+metrics_cli_init(void)
+{
+ shell_register("metrics", metrics_commands);
+
+ return 0;
+}
diff --git a/sys/metrics/src/metrics.c b/sys/metrics/src/metrics.c
new file mode 100644
index 0000000000..73b1e39b61
--- /dev/null
+++ b/sys/metrics/src/metrics.c
@@ -0,0 +1,563 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "sysinit/sysinit.h"
+#include "syscfg/syscfg.h"
+#include "os/os.h"
+#include "metrics/metrics.h"
+#include "tinycbor/cbor.h"
+#include "tinycbor/cbor_mbuf_writer.h"
+#include "log/log.h"
+#include "metrics_priv.h"
+
+#define MBUF_MEMBLOCK_OVERHEAD \
+ (sizeof(struct os_mbuf))
+
+#define MEMPOOL_COUNT MYNEWT_VAL(METRICS_POOL_COUNT)
+#define MEMPOOL_SIZE MYNEWT_VAL(METRICS_POOL_SIZE)
+
+#define METRICS_TYPE_SERIES_MASK 0x80
+#define METRICS_TYPE_SIGNED_MASK 0x40
+#define METRICS_TYPE_SIZE_MASK 0x0f
+
+union metrics_metric_val {
+ uintptr_t notused;
+ uint32_t val;
+ struct os_mbuf *series;
+};
+
+struct metrics_event {
+ struct metrics_event_hdr hdr;
+ union metrics_metric_val vals[0];
+};
+
+/*
+ * This is aligned size for mempool block to make sure we do not write series
+ * data across mbuf boundary in chain - it simplifies code a lot.
+ */
+#define MEMPOOL_SIZE_ALIGNED \
+ OS_ALIGN(MBUF_MEMBLOCK_OVERHEAD + MEMPOOL_SIZE, sizeof(uint32_t))
+
+static os_membuf_t event_metric_data[ OS_MEMPOOL_SIZE(MEMPOOL_COUNT, MEMPOOL_SIZE) ];
+static struct os_mbuf_pool event_metric_mbuf_pool;
+static struct os_mempool event_metric_mempool;
+
+int
+metrics_event_init(struct metrics_event_hdr *hdr,
+ const struct metrics_metric_def *metrics, uint8_t count,
+ const char *name)
+{
+ assert((count > 0) && (count <= 32));
+
+ memset(hdr, 0, sizeof(*hdr) + count * sizeof(union metrics_metric_val));
+ hdr->name = name;
+ hdr->count = count;
+ hdr->defs = metrics;
+ hdr->enabled = UINT32_MAX;
+
+ return 0;
+}
+
+int
+metrics_event_register(struct metrics_event_hdr *hdr)
+{
+ return metrics_cli_register_event(hdr);
+}
+
+int
+metrics_event_set_log(struct metrics_event_hdr *hdr, struct log *log,
+ int module, int level)
+{
+ hdr->log = log;
+ hdr->log_module = module;
+ hdr->log_level = level;
+
+ return 0;
+}
+
+int
+metrics_event_start(struct metrics_event_hdr *hdr, uint32_t timestamp)
+{
+ if (hdr->set) {
+ metrics_event_end(hdr);
+ }
+
+ hdr->timestamp = timestamp;
+
+ return 0;
+}
+
+int
+metrics_event_end(struct metrics_event_hdr *hdr)
+{
+ struct metrics_event *em = (struct metrics_event *)hdr;
+ const struct metrics_metric_def *def;
+ union metrics_metric_val *v;
+ struct os_mbuf *om;
+ int ret;
+ int i;
+
+ if (hdr->log) {
+ om = metrics_get_mbuf();
+ if (om) {
+ os_mbuf_extend(om, sizeof(struct log_entry_hdr));
+ if (!metrics_event_to_cbor(hdr, om)) {
+ log_append_mbuf_typed(hdr->log, hdr->log_module, hdr->log_level,
+ LOG_ETYPE_CBOR, om);
+ } else {
+ os_mbuf_free_chain(om);
+ ret = -1;
+ }
+ } else {
+ ret = -1;
+ }
+ }
+
+ hdr->set = 0;
+
+ for (i = 0; i < hdr->count; i++) {
+ def = &hdr->defs[i];
+ v = &em->vals[i];
+
+ if (def->type & METRICS_TYPE_SERIES_MASK) {
+ if (v->series) {
+ os_mbuf_free_chain(v->series);
+ }
+ v->series = NULL;
+ } else {
+ v->val = 0;
+ }
+ }
+
+ return ret;
+}
+
+int
+metrics_set_state(struct metrics_event_hdr *hdr, uint8_t metric, bool state)
+{
+ assert(metric < hdr->count);
+
+ if (state) {
+ hdr->enabled |= (1 << metric);
+ } else {
+ hdr->enabled &= ~(1 << metric);
+ }
+
+ return 0;
+}
+
+int
+metrics_set_state_mask(struct metrics_event_hdr *hdr, uint32_t mask)
+{
+ hdr->enabled |= mask;
+
+ return 0;
+}
+
+int
+metrics_clr_state_mask(struct metrics_event_hdr *hdr, uint32_t mask)
+{
+ hdr->enabled &= ~mask;
+
+ return 0;
+}
+
+uint32_t
+metrics_get_state_mask(struct metrics_event_hdr *hdr)
+{
+ return hdr->enabled;
+}
+
+static int
+set_single_value(struct metrics_event_hdr *hdr, uint8_t metric,
+ uint32_t val)
+{
+ struct metrics_event *em = (struct metrics_event *)hdr;
+ union metrics_metric_val *v;
+
+ v = &em->vals[metric];
+ v->val = val;
+
+ hdr->set |= (1 << metric);
+
+ return 0;
+}
+
+static int
+set_series_value(struct metrics_event_hdr *hdr, uint8_t metric,
+ uint32_t val, uint8_t type)
+{
+ struct metrics_event *em = (struct metrics_event *)hdr;
+ union metrics_metric_val *v;
+ uint16_t type_len;
+
+ v = &em->vals[metric];
+
+ if (!v->series) {
+ v->series = os_mbuf_get(&event_metric_mbuf_pool, 0);
+ }
+
+ val = htole32(val);
+ type_len = type & METRICS_TYPE_SIZE_MASK;
+ assert((type_len == 1) || (type_len == 2) || (type_len == 4));
+
+ os_mbuf_append(v->series, &val, type_len);
+
+ hdr->set |= (1 << metric);
+
+ return 0;
+}
+
+int
+metrics_set_value(struct metrics_event_hdr *hdr, uint8_t metric,
+ uint32_t val)
+{
+ const struct metrics_metric_def *def;
+
+ assert(metric < hdr->count);
+
+ if ((hdr->enabled & (1 << metric)) == 0) {
+ return 0;
+ }
+
+ def = &hdr->defs[metric];
+
+ if (def->type & METRICS_TYPE_SERIES_MASK) {
+ return set_series_value(hdr, metric, val, def->type);
+ } else {
+ return set_single_value(hdr, metric, val);
+ }
+
+ return -1;
+}
+
+int
+metrics_set_single_value(struct metrics_event_hdr *hdr, uint8_t metric, uint32_t val)
+{
+ const struct metrics_metric_def *def;
+
+ assert(metric < hdr->count);
+
+ def = &hdr->defs[metric];
+ if (def->type & METRICS_TYPE_SERIES_MASK) {
+ return -1;
+ }
+
+ if ((hdr->enabled & (1 << metric)) == 0) {
+ return 0;
+ }
+
+ return set_single_value(hdr, metric, val);
+}
+
+int
+metrics_set_series_value(struct metrics_event_hdr *hdr, uint8_t metric, uint32_t val)
+{
+ const struct metrics_metric_def *def;
+
+ assert(metric < hdr->count);
+
+ def = &hdr->defs[metric];
+ if ((def->type & METRICS_TYPE_SERIES_MASK) == 0) {
+ return -1;
+ }
+
+ if ((hdr->enabled & (1 << metric)) == 0) {
+ return 0;
+ }
+
+ return set_series_value(hdr, metric, val, def->type);
+}
+
+static int
+append_series_u8_to_cbor(CborEncoder *encoder, struct os_mbuf *om)
+{
+ uint8_t *ptr;
+
+ while (om) {
+ ptr = om->om_data;
+
+ while (ptr < om->om_data + om->om_len) {
+ if (cbor_encode_uint(encoder, *ptr)) {
+ return -1;
+ }
+ ptr += sizeof(uint8_t);
+ }
+
+ om = SLIST_NEXT(om, om_next);
+ }
+
+ return 0;
+}
+
+static int
+append_series_s8_to_cbor(CborEncoder *encoder, struct os_mbuf *om)
+{
+ uint8_t *ptr;
+
+ while (om) {
+ ptr = om->om_data;
+
+ while (ptr < om->om_data + om->om_len) {
+ if (cbor_encode_int(encoder, (int8_t)*ptr)) {
+ return -1;
+ }
+ ptr += sizeof(uint8_t);
+ }
+
+ om = SLIST_NEXT(om, om_next);
+ }
+
+ return 0;
+}
+
+static int
+append_series_u16_to_cbor(CborEncoder *encoder, struct os_mbuf *om)
+{
+ uint16_t u16;
+ uint8_t *ptr;
+
+ while (om) {
+ ptr = om->om_data;
+
+ while (ptr < om->om_data + om->om_len) {
+ memcpy(&u16, ptr, sizeof(uint16_t));
+ u16 = le16toh(u16);
+ if (cbor_encode_uint(encoder, u16)) {
+ return -1;
+ }
+ ptr += sizeof(uint16_t);
+ }
+
+ om = SLIST_NEXT(om, om_next);
+ }
+
+ return 0;
+}
+
+static int
+append_series_s16_to_cbor(CborEncoder *encoder, struct os_mbuf *om)
+{
+ int16_t s16;
+ uint8_t *ptr;
+
+ while (om) {
+ ptr = om->om_data;
+
+ while (ptr < om->om_data + om->om_len) {
+ memcpy(&s16, ptr, sizeof(int16_t));
+ s16 = le16toh(s16);
+ if (cbor_encode_int(encoder, s16)) {
+ return -1;
+ }
+ ptr += sizeof(int16_t);
+ }
+
+ om = SLIST_NEXT(om, om_next);
+ }
+
+ return 0;
+}
+
+static int
+append_series_u32_to_cbor(CborEncoder *encoder, struct os_mbuf *om)
+{
+ uint32_t u32;
+ uint8_t *ptr;
+
+ while (om) {
+ ptr = om->om_data;
+
+ while (ptr < om->om_data + om->om_len) {
+ memcpy(&u32, ptr, sizeof(uint32_t));
+ u32 = le32toh(u32);
+ if (cbor_encode_uint(encoder, u32)) {
+ return -1;
+ }
+ ptr += sizeof(uint32_t);
+ }
+
+ om = SLIST_NEXT(om, om_next);
+ }
+
+ return 0;
+}
+
+static int
+append_series_s32_to_cbor(CborEncoder *encoder, struct os_mbuf *om)
+{
+ int32_t s32;
+ uint8_t *ptr;
+
+ while (om) {
+ ptr = om->om_data;
+
+ while (ptr < om->om_data + om->om_len) {
+ memcpy(&s32, ptr, sizeof(int32_t));
+ s32 = le32toh(s32);
+ if (cbor_encode_int(encoder, s32)) {
+ return -1;
+ }
+ ptr += sizeof(int32_t);
+ }
+
+ om = SLIST_NEXT(om, om_next);
+ }
+
+ return 0;
+}
+
+int
+metrics_event_to_cbor(struct metrics_event_hdr *hdr, struct os_mbuf *om)
+{
+ struct metrics_event *em = (struct metrics_event *)hdr;
+ const struct metrics_metric_def *def;
+ union metrics_metric_val *v;
+ struct cbor_mbuf_writer writer;
+ struct CborEncoder encoder;
+ struct CborEncoder map;
+ struct CborEncoder arr;
+ int i;
+ int rc;
+
+ cbor_mbuf_writer_init(&writer, om);
+ cbor_encoder_init(&encoder, &writer.enc, 0);
+
+ rc = cbor_encoder_create_map(&encoder, &map, CborIndefiniteLength);
+ if (rc != 0) {
+ goto failed;
+ }
+
+ cbor_encode_text_stringz(&map, "ev");
+ cbor_encode_text_stringz(&map, hdr->name);
+
+ cbor_encode_text_stringz(&map, "ts");
+ cbor_encode_uint(&map, hdr->timestamp);
+
+ for (i = 0; i < hdr->count; i++) {
+ /* Skip if not enabled */
+ if ((hdr->enabled & (1 << i)) == 0) {
+ continue;
+ }
+
+ def = &hdr->defs[i];
+ v = &em->vals[i];
+ cbor_encode_text_stringz(&map, def->name);
+
+ /* Write as null if value was not set */
+ if ((hdr->set & (1 << i)) == 0) {
+ cbor_encode_null(&map);
+ continue;
+ }
+
+ if ((def->type & METRICS_TYPE_SERIES_MASK) == 0) {
+ if (def->type & METRICS_TYPE_SIGNED_MASK) {
+ cbor_encode_int(&map, (int32_t)v->val);
+ } else {
+ cbor_encode_uint(&map, v->val);
+ }
+ continue;
+ }
+
+ rc = cbor_encoder_create_array(&map, &arr, CborIndefiniteLength);
+ if (rc != 0) {
+ goto failed;
+ }
+
+ switch (def->type) {
+ case METRICS_TYPE_SERIES_U8:
+ append_series_u8_to_cbor(&arr, v->series);
+ break;
+ case METRICS_TYPE_SERIES_S8:
+ append_series_s8_to_cbor(&arr, v->series);
+ break;
+ case METRICS_TYPE_SERIES_U16:
+ append_series_u16_to_cbor(&arr, v->series);
+ break;
+ case METRICS_TYPE_SERIES_S16:
+ append_series_s16_to_cbor(&arr, v->series);
+ break;
+ case METRICS_TYPE_SERIES_U32:
+ append_series_u32_to_cbor(&arr, v->series);
+ break;
+ case METRICS_TYPE_SERIES_S32:
+ append_series_s32_to_cbor(&arr, v->series);
+ break;
+ default:
+ assert(0);
+ }
+
+ rc = cbor_encoder_close_container(&map, &arr);
+ if (rc != 0) {
+ goto failed;
+ }
+
+ /*
+ * Let's remove existing series chain to free space in case om is from
+ * event_metric pool - assume we do this at the end of event so will
+ * start over anyway.
+ */
+ if (om->om_omp == &event_metric_mbuf_pool) {
+ os_mbuf_free_chain(v->series);
+ v->series = NULL;
+ }
+ }
+
+ rc = cbor_encoder_close_container(&encoder, &map);
+ if (rc != 0) {
+ goto failed;
+ }
+
+ return 0;
+
+failed:
+ os_mbuf_free_chain(om);
+
+ return -1;
+}
+
+struct os_mbuf *
+metrics_get_mbuf(void)
+{
+ return os_mbuf_get(&event_metric_mbuf_pool, 0);
+}
+
+void
+metrics_pkg_init(void)
+{
+ int rc;
+
+ SYSINIT_ASSERT_ACTIVE();
+
+ rc = os_mempool_init(&event_metric_mempool, MEMPOOL_COUNT, MEMPOOL_SIZE,
+ event_metric_data, "event_metric");
+ assert(rc == 0);
+
+ rc = os_mbuf_pool_init(&event_metric_mbuf_pool, &event_metric_mempool,
+ MEMPOOL_SIZE, MEMPOOL_COUNT);
+ assert(rc == 0);
+
+#if MYNEWT_VAL(METRICS_CLI)
+ metrics_cli_init();
+#endif
+}
diff --git a/sys/metrics/src/metrics_priv.h b/sys/metrics/src/metrics_priv.h
new file mode 100644
index 0000000000..f8c2b20191
--- /dev/null
+++ b/sys/metrics/src/metrics_priv.h
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef __METRICS_PRIV_H__
+#define __METRICS_PRIV_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int metrics_cli_init(void);
+int metrics_cli_register_event(struct metrics_event_hdr *hdr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __METRICS_PRIV_H__ */
diff --git a/sys/metrics/syscfg.yml b/sys/metrics/syscfg.yml
new file mode 100644
index 0000000000..4ae386b205
--- /dev/null
+++ b/sys/metrics/syscfg.yml
@@ -0,0 +1,31 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Package: sys/metrics
+
+syscfg.defs:
+ METRICS_POOL_SIZE:
+ description: Block size for metrics' mempool
+ value: 64
+ METRICS_POOL_COUNT:
+ description: Block count for metrics' mempool
+ value: 100
+
+ METRICS_CLI:
+ description: Enable shell interface
+ value: 0
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services