1 /*************************************************************************//**
3 * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
5 * Unless otherwise specified, all software contained herein is
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 * ECOMP is a trademark and service mark of AT&T Intellectual Property.
17 ****************************************************************************/
19 /**************************************************************************//**
21 * Implementation of EVEL functions relating to the Measurement for VF
24 * @note This is an experimental event tytpe and does not form part of the
25 * currently approved AT&T event schema. It is intended to allow a
26 * less-onerous event reporting mechanism because it avoids having to
27 * return all the platform statistics which are mandatory in the
28 * **measurementsForVfScaling** event.
29 ****************************************************************************/
36 #include "evel_internal.h"
37 #include "evel_throttle.h"
39 /**************************************************************************//**
40 * Create a new Report event.
42 * @note The mandatory fields on the Report must be supplied to this
43 * factory function and are immutable once set. Optional fields have
44 * explicit setter functions, but again values may only be set once so
45 * that the Report has immutable properties.
47 * @param measurement_interval
48 * @param event_name Unique Event Name
49 * @param event_id A universal identifier of the event for analysis etc
50 * @returns pointer to the newly manufactured ::EVENT_REPORT. If the event is
51 * not used (i.e. posted) it must be released using ::evel_free_event.
52 * @retval NULL Failed to create the event.
53 *****************************************************************************/
54 EVENT_REPORT * evel_new_report(double measurement_interval,const char *ev_name, const char *ev_id)
56 EVENT_REPORT * report = NULL;
60 /***************************************************************************/
61 /* Check preconditions. */
62 /***************************************************************************/
63 assert(measurement_interval >= 0.0);
65 /***************************************************************************/
66 /* Allocate the report. */
67 /***************************************************************************/
68 report = malloc(sizeof(EVENT_REPORT));
71 log_error_state("Out of memory for Report");
74 memset(report, 0, sizeof(EVENT_REPORT));
75 EVEL_DEBUG("New report is at %lp", report);
77 /***************************************************************************/
78 /* Initialize the header & the report fields. */
79 /***************************************************************************/
80 evel_init_header_nameid(&report->header,ev_name,ev_id);
81 report->header.event_domain = EVEL_DOMAIN_REPORT;
82 report->measurement_interval = measurement_interval;
84 dlist_initialize(&report->feature_usage);
85 dlist_initialize(&report->measurement_groups);
86 report->major_version = EVEL_REPORT_MAJOR_VERSION;
87 report->minor_version = EVEL_REPORT_MINOR_VERSION;
94 /**************************************************************************//**
95 * Set the Event Type property of the Report.
97 * @note The property is treated as immutable: it is only valid to call
98 * the setter once. However, we don't assert if the caller tries to
99 * overwrite, just ignoring the update instead.
101 * @param report Pointer to the Report.
102 * @param type The Event Type to be set. ASCIIZ string. The caller
103 * does not need to preserve the value once the function
105 *****************************************************************************/
106 void evel_report_type_set(EVENT_REPORT * report,
107 const char * const type)
111 /***************************************************************************/
112 /* Check preconditions and call evel_header_type_set. */
113 /***************************************************************************/
114 assert(report != NULL);
115 assert(report->header.event_domain == EVEL_DOMAIN_REPORT);
116 evel_header_type_set(&report->header, type);
121 /**************************************************************************//**
122 * Add a Feature usage value name/value pair to the Report.
124 * The name is null delimited ASCII string. The library takes
125 * a copy so the caller does not have to preserve values after the function
128 * @param report Pointer to the report.
129 * @param feature ASCIIZ string with the feature's name.
130 * @param utilization Utilization of the feature.
131 *****************************************************************************/
132 void evel_report_feature_use_add(EVENT_REPORT * report,
136 MEASUREMENT_FEATURE_USE * feature_use = NULL;
139 /***************************************************************************/
140 /* Check assumptions. */
141 /***************************************************************************/
142 assert(report != NULL);
143 assert(report->header.event_domain == EVEL_DOMAIN_REPORT);
144 assert(feature != NULL);
145 assert(utilization >= 0);
147 /***************************************************************************/
148 /* Allocate a container for the value and push onto the list. */
149 /***************************************************************************/
150 EVEL_DEBUG("Adding Feature=%s Use=%d", feature, utilization);
151 feature_use = malloc(sizeof(MEASUREMENT_FEATURE_USE));
152 assert(feature_use != NULL);
153 memset(feature_use, 0, sizeof(MEASUREMENT_FEATURE_USE));
154 feature_use->feature_id = strdup(feature);
155 assert(feature_use->feature_id != NULL);
156 feature_use->feature_utilization = utilization;
158 dlist_push_last(&report->feature_usage, feature_use);
163 /**************************************************************************//**
164 * Add a Additional Measurement value name/value pair to the Report.
166 * The name is null delimited ASCII string. The library takes
167 * a copy so the caller does not have to preserve values after the function
170 * @param report Pointer to the report.
171 * @param group ASCIIZ string with the measurement group's name.
172 * @param name ASCIIZ string containing the measurement's name.
173 * @param value ASCIIZ string containing the measurement's value.
174 *****************************************************************************/
175 void evel_report_custom_measurement_add(EVENT_REPORT * report,
176 const char * const group,
177 const char * const name,
178 const char * const value)
180 MEASUREMENT_GROUP * measurement_group = NULL;
181 CUSTOM_MEASUREMENT * measurement = NULL;
182 DLIST_ITEM * item = NULL;
185 /***************************************************************************/
186 /* Check assumptions. */
187 /***************************************************************************/
188 assert(report != NULL);
189 assert(report->header.event_domain == EVEL_DOMAIN_REPORT);
190 assert(group != NULL);
191 assert(name != NULL);
192 assert(value != NULL);
194 /***************************************************************************/
195 /* Allocate a container for the name/value pair. */
196 /***************************************************************************/
197 EVEL_DEBUG("Adding Measurement Group=%s Name=%s Value=%s",
199 measurement = malloc(sizeof(CUSTOM_MEASUREMENT));
200 assert(measurement != NULL);
201 memset(measurement, 0, sizeof(CUSTOM_MEASUREMENT));
202 measurement->name = strdup(name);
203 assert(measurement->name != NULL);
204 measurement->value = strdup(value);
205 assert(measurement->value != NULL);
207 /***************************************************************************/
208 /* See if we have that group already. */
209 /***************************************************************************/
210 item = dlist_get_first(&report->measurement_groups);
213 measurement_group = (MEASUREMENT_GROUP *) item->item;
214 assert(measurement_group != NULL);
216 EVEL_DEBUG("Got measurement group %s", measurement_group->name);
217 if (strcmp(group, measurement_group->name) == 0)
219 EVEL_DEBUG("Found existing Measurement Group");
222 item = dlist_get_next(item);
225 /***************************************************************************/
226 /* If we didn't have the group already, create it. */
227 /***************************************************************************/
230 EVEL_DEBUG("Creating new Measurement Group");
231 measurement_group = malloc(sizeof(MEASUREMENT_GROUP));
232 assert(measurement_group != NULL);
233 memset(measurement_group, 0, sizeof(MEASUREMENT_GROUP));
234 measurement_group->name = strdup(group);
235 assert(measurement_group->name != NULL);
236 dlist_initialize(&measurement_group->measurements);
237 dlist_push_last(&report->measurement_groups, measurement_group);
240 /***************************************************************************/
241 /* If we didn't have the group already, create it. */
242 /***************************************************************************/
243 dlist_push_last(&measurement_group->measurements, measurement);
248 /**************************************************************************//**
249 * Encode the report as a JSON report.
251 * @param jbuf Pointer to the ::EVEL_JSON_BUFFER to encode into.
252 * @param event Pointer to the ::EVENT_HEADER to encode.
253 *****************************************************************************/
254 void evel_json_encode_report(EVEL_JSON_BUFFER * jbuf,
255 EVENT_REPORT * event)
257 MEASUREMENT_FEATURE_USE * feature_use = NULL;
258 MEASUREMENT_GROUP * measurement_group = NULL;
259 CUSTOM_MEASUREMENT * custom_measurement = NULL;
260 DLIST_ITEM * item = NULL;
261 DLIST_ITEM * nested_item = NULL;
265 /***************************************************************************/
266 /* Check preconditions. */
267 /***************************************************************************/
268 assert(event != NULL);
269 assert(event->header.event_domain == EVEL_DOMAIN_REPORT);
271 evel_json_encode_header(jbuf, &event->header);
272 evel_json_open_named_object(jbuf, "measurementsForVfReportingFields");
273 evel_enc_kv_double(jbuf, "measurementInterval", event->measurement_interval);
275 /***************************************************************************/
276 /* Feature Utilization list. */
277 /***************************************************************************/
278 evel_json_checkpoint(jbuf);
279 if (evel_json_open_opt_named_list(jbuf, "featureUsageArray"))
281 bool item_added = false;
283 item = dlist_get_first(&event->feature_usage);
286 feature_use = (MEASUREMENT_FEATURE_USE*) item->item;
287 assert(feature_use != NULL);
289 if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec,
291 feature_use->feature_id))
293 evel_json_open_object(jbuf);
294 evel_enc_kv_string(jbuf, "featureIdentifier", feature_use->feature_id);
296 jbuf, "featureUtilization", feature_use->feature_utilization);
297 evel_json_close_object(jbuf);
300 item = dlist_get_next(item);
302 evel_json_close_list(jbuf);
304 /*************************************************************************/
305 /* If we've not written anything, rewind to before we opened the list. */
306 /*************************************************************************/
309 evel_json_rewind(jbuf);
313 /***************************************************************************/
314 /* Additional Measurement Groups list. */
315 /***************************************************************************/
316 evel_json_checkpoint(jbuf);
317 if (evel_json_open_opt_named_list(jbuf, "additionalMeasurements"))
319 bool item_added = false;
321 item = dlist_get_first(&event->measurement_groups);
324 measurement_group = (MEASUREMENT_GROUP *) item->item;
325 assert(measurement_group != NULL);
327 if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec,
328 "additionalMeasurements",
329 measurement_group->name))
331 evel_json_open_object(jbuf);
332 evel_enc_kv_string(jbuf, "name", measurement_group->name);
333 evel_json_open_named_list(jbuf, "measurements");
335 /*********************************************************************/
336 /* Measurements list. */
337 /*********************************************************************/
338 nested_item = dlist_get_first(&measurement_group->measurements);
339 while (nested_item != NULL)
341 custom_measurement = (CUSTOM_MEASUREMENT *) nested_item->item;
342 assert(custom_measurement != NULL);
344 evel_json_open_object(jbuf);
345 evel_enc_kv_string(jbuf, "name", custom_measurement->name);
346 evel_enc_kv_string(jbuf, "value", custom_measurement->value);
347 evel_json_close_object(jbuf);
348 nested_item = dlist_get_next(nested_item);
350 evel_json_close_list(jbuf);
351 evel_json_close_object(jbuf);
354 item = dlist_get_next(item);
356 evel_json_close_list(jbuf);
358 /*************************************************************************/
359 /* If we've not written anything, rewind to before we opened the list. */
360 /*************************************************************************/
363 evel_json_rewind(jbuf);
367 /***************************************************************************/
368 /* Although optional, we always generate the version. Note that this */
369 /* closes the object, too. */
370 /***************************************************************************/
371 evel_enc_version(jbuf,
372 "measurementFieldsVersion",
373 event->major_version,
374 event->minor_version);
375 evel_json_close_object(jbuf);
380 /**************************************************************************//**
383 * Free off the Report supplied. Will free all the contained allocated memory.
385 * @note It does not free the Report itself, since that may be part of a
387 *****************************************************************************/
388 void evel_free_report(EVENT_REPORT * event)
390 MEASUREMENT_FEATURE_USE * feature_use = NULL;
391 MEASUREMENT_GROUP * measurement_group = NULL;
392 CUSTOM_MEASUREMENT * custom_measurement = NULL;
396 /***************************************************************************/
397 /* Check preconditions. As an internal API we don't allow freeing NULL */
398 /* events as we do on the public API. */
399 /***************************************************************************/
400 assert(event != NULL);
401 assert(event->header.event_domain == EVEL_DOMAIN_REPORT);
403 /***************************************************************************/
404 /* Free all internal strings then the header itself. */
405 /***************************************************************************/
406 feature_use = dlist_pop_last(&event->feature_usage);
407 while (feature_use != NULL)
409 EVEL_DEBUG("Freeing Feature use Info (%s)", feature_use->feature_id);
410 free(feature_use->feature_id);
412 feature_use = dlist_pop_last(&event->feature_usage);
414 measurement_group = dlist_pop_last(&event->measurement_groups);
415 while (measurement_group != NULL)
417 EVEL_DEBUG("Freeing Measurement Group (%s)", measurement_group->name);
419 custom_measurement = dlist_pop_last(&measurement_group->measurements);
420 while (custom_measurement != NULL)
422 EVEL_DEBUG("Freeing mesaurement (%s)", custom_measurement->name);
424 free(custom_measurement->name);
425 free(custom_measurement->value);
426 free(custom_measurement);
427 custom_measurement = dlist_pop_last(&measurement_group->measurements);
430 free(measurement_group->name);
431 free(measurement_group);
432 measurement_group = dlist_pop_last(&event->measurement_groups);
435 evel_free_header(&event->header);