1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
|
# Quick Start Guide {#quickstart}
# Introduction {#qs_intro}
This Quick-Start section describes how to:
* Install and compile the supplied library code
* Integrate an existing project to use the EVEL library
# Installation {#qs_install}
The library is supplied as a source-code compressed-tar file. It is
straightforward to install and build to integrate with an existing or new
development project.
## Unpack the Source Code {#qs_unpack}
The file should unpacked into your development environment:
```
$ mkdir evel
$ cd evel
$ tar zxvf evel-library-package.tgz
```
### Satisfy Dependencies {#qs_depend}
Note that all commands in this section are based on CentOS package management
tools and you may need to substitute the appropriate tools/packages for your
distribution, for example `apt-get` for Ubuntu.
Ensure that GCC development tools are available.
```
$ sudo yum install gcc
```
Additionally, the library has a dependency on the cURL library, so you'll need
the development tools for libCurl installed. (At runtime, only the runtime
library is required, of course.)
```
$ sudo yum install libcurl-devel
```
If you wish to make the project documentation, then Doxygen and Graphviz are
required. (Again, this is only in the development environment, not the runtime
environment!)
```
$ sudo yum install doxygen graphviz
```
Note that some distributions have quite old versions of Doxygen by default and
it may be necessary to install a later version to use all the features.
If you want to build PDFs from the LaTeX you will need a texlive install.
```
$ sudo yum install texlive
```
### Test Build {#qs_build}
Make sure that the library makes cleanly:
```
$ cd bldjobs
$ make
Making dependency file evel_unit.d for evel_unit.c
Making dependency file evel_test_control.d for evel_test_control.c
Making dependency file evel_demo.d for evel_demo.c
Making dependency file jsmn.d for jsmn.c
Making dependency file evel_logging.d for evel_logging.c
Making dependency file evel_event_mgr.d for evel_event_mgr.c
Making dependency file evel_internal_event.d for evel_internal_event.c
Making dependency file evel_throttle.d for evel_throttle.c
Making dependency file evel_syslog.d for evel_syslog.c
Making dependency file evel_strings.d for evel_strings.c
Making dependency file evel_state_change.d for evel_state_change.c
Making dependency file evel_scaling_measurement.d for evel_scaling_measurement.c
Making dependency file evel_signaling.d for evel_signaling.c
Making dependency file evel_service.d for evel_service.c
Making dependency file evel_reporting_measurement.d for evel_reporting_measurement.c
Making dependency file evel_json_buffer.d for evel_json_buffer.c
Making dependency file evel_other.d for evel_other.c
Making dependency file evel_option.d for evel_option.c
Making dependency file evel_mobile_flow.d for evel_mobile_flow.c
Making dependency file evel_fault.d for evel_fault.c
Making dependency file evel_event.d for evel_event.c
Making dependency file double_list.d for double_list.c
Making dependency file ring_buffer.d for ring_buffer.c
Making dependency file metadata.d for metadata.c
Making dependency file evel.d for evel.c
Making evel.o from evel.c
Making metadata.o from metadata.c
Making ring_buffer.o from ring_buffer.c
Making double_list.o from double_list.c
Making evel_event.o from evel_event.c
Making evel_fault.o from evel_fault.c
Making evel_mobile_flow.o from evel_mobile_flow.c
Making evel_option.o from evel_option.c
Making evel_other.o from evel_other.c
Making evel_json_buffer.o from evel_json_buffer.c
Making evel_reporting_measurement.o from evel_reporting_measurement.c
Making evel_service.o from evel_service.c
Making evel_signaling.o from evel_signaling.c
Making evel_scaling_measurement.o from evel_scaling_measurement.c
Making evel_state_change.o from evel_state_change.c
Making evel_strings.o from evel_strings.c
Making evel_syslog.o from evel_syslog.c
Making evel_throttle.o from evel_throttle.c
Making evel_internal_event.o from evel_internal_event.c
Making evel_event_mgr.o from evel_event_mgr.c
Making evel_logging.o from evel_logging.c
Making jsmn.o from jsmn.c
Linking API Shared Library
Linking API Static Library
Making evel_demo.o from evel_demo.c
Making evel_test_control.o from evel_test_control.c
Linking EVEL demo
Making EVEL training
$
```
You should now be able to run the demo CLI application. Since it will want to
dynamically link to the library that you've just made, you will need to set
your `LD_LIBRARY_PATH` appropriately first. Make sure that you specify
your actual directory paths correctly in the following:
```
$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/centos/evel/libs/x86_64
$ ../output/x86_64/evel_demo
evel_demo [--help]
--fqdn <domain>
--port <port_number>
[--path <path>]
[--topic <topic>]
[--username <username>]
[--password <password>]
[--https]
[--cycles <cycles>]
[--nothrott]
Demonstrate use of the ECOMP Vendor Event Listener API.
-h Display this usage message.
--help
-f The FQDN or IP address to the RESTful API.
--fqdn
-n The port number the RESTful API.
--port
-p The optional path prefix to the RESTful API.
--path
-t The optional topic part of the RESTful API.
--topic
-u The optional username for basic authentication of requests.
--username
-w The optional password for basic authentication of requests.
--password
-s Use HTTPS rather than HTTP for the transport.
--https
-c Loop <cycles> times round the main loop. Default = 1.
--cycles
-v Generate much chattier logs.
--verbose
-x Exclude throttling commands from demonstration.
--nothrott
$
```
Assuming that all worked as expected, you are ready to start integrating with
your application. It probably makes sense to make the LD_LIBRARY_PATH change
above permanent by incorporating it into your `.bash_profile` file.
### Project Documentation {#qs_build_docs}
The source comes with its own documentation included. The documentation can be
built using the `docs` target in the Makefile. By default this builds HTML
and LaTeX documentation, the latter being used to prepare PDFs.
To make the documentation:
```
$ cd bldjobs
$ make docs
Cleaning docs...
Making Doxygen documentation
$
```
There is a make target that is intended to install the documentation on a
"team server" - it will need adaptation for your team's environment - see the
`docs_install` target in the Makefile:
```
$ make docs_install
Cleaning docs...
Making Doxygen documentation
Copying docs to team web-server...
Enter passphrase for key '/data/home/.ssh/id_rsa':
annotated.html 100% 8088 7.9KB/s 00:00
arrowdown.png 100% 246 0.2KB/s 00:00
arrowright.png 100% 229 0.2KB/s 00:00
...
$
```
# Project Integration {#qs_integrate}
There are two key steps to the integration which have to be undertaken:
* Initialization/Termination of the library.
* Creation & posting of individual events.
Additionally, it may be necessary to consider changes to the EVEL library's
source code if assumptions made by the library are either not satisfied or
inconvenient. In particular:
* If the project already uses libcurl then the global initialization of the
library should be removed from the _EVEL Library_.
* The _EVEL Library_ uses `syslog` for event logging. If the project uses a
different event logging process, then EVEL's event logging macros should be
rewritten appropriately.
These steps are considered in the [Normal Use](@ref qs_normal_use) and
[EVEL Adaptation](@ref qs_adaptation) sections below.
## Normal Use {#qs_normal_use}
The _EVEL Library_ should be integrated with your project at a per-process
level: each process is an independent client of the ECOMP Vendor Event Listener
API.
### Initialization {#qs_initialize}
The _EVEL Library_ should be initialized before the process becomes
multi-threaded. This constraint arises from the use of libcurl which imposes
the constraint that initialization occurs before the system is multi-threaded.
This is described in more detail in the libcurl documentation for the
[curl_global_init](https://curl.haxx.se/libcurl/c/curl_global_init.html)
function.
Initialization stores configuration of the Vendor Event Listener API's details,
such as the FQDN or IP address of the service, so the initializing process must
have either extracted this information from its configuration or have this
information "hard-wired" into the application, so that it is available at the
point the `evel_initialize()` function is called:
```C
#include "evel.h"
...
if(evel_initialize(fqdn, /* FQDN */
port, /* Port */
NULL, /* Backup FQDN */
0, /* Backup port */
NULL, /* optional path */
NULL, /* optional topic */
100, /* Ring Buffer size */
0, /* HTTPS? */
0, /* active mode? */
NULL, /* cert file */
NULL, /* key file */
NULL, /* ca info */
NULL, /* ca file */
0, /* verify peer */
0, /* verify host */
"", /* Username */
"", /* Password */
"", /* Username2 */
"", /* Password2 */
NULL, /* Source ip */
NULL, /* Source ip2 */
EVEL_SOURCE_VIRTUAL_MACHINE, /* Source type */
"EVEL demo client", /* Role */
verbose_mode)) /* Verbosity */
{
fprintf(stderr, "Failed to initialize the EVEL library!!!");
exit(-1);
}
...
```
Once initialization has occurred successfully, the application may raise events
and may also use the logging functions such as EVEL_INFO().
Initialization is entirely local (there is no interaction with the service) so
it is very unlikely to fail, unless the application environment is seriously
degraded.
### Event Generation {#qs_generate}
Generating events is a two stage process:
1. Firstly, the _EVEL Library_ is called to allocate an event of the correct
type.
* If this is successful, the caller is given a pointer to the event.
* All mandatory fields on the event are provided to this factory function
and are thereafter immutable.
* The application may add any necessary optional fields to the event, using
the pointer previously returned.
2. The event is sent to the JSON API using the evel_post_event() function.
* At this point, the application relinquishes all responsibility for the
event:
* It will be posted to the JSON API, if possible.
* Whether or not the posting is successful, the memory used will be
freed.
In practice this looks like:
```C
#include "evel.h"
...
/***************************************************************************/
/* Create a new Fault object, setting mandatory fields as we do so... */
/***************************************************************************/
fault = evel_new_fault("fault_eNodeB_alarm",
"fault000000001",
"My alarm condition",
"It broke very badly",
EVEL_PRIORITY_NORMAL,
EVEL_SEVERITY_MAJOR,
EVEL_SOURCE_HOST,
EVEL_VF_STATUS_READY_TERMINATE);
if (fault != NULL)
{
/*************************************************************************/
/* We have a Fault object - add some optional fields to it... */
/*************************************************************************/
evel_fault_type_set(fault, "Bad things happen...");
evel_fault_interface_set(fault, "My Interface Card");
evel_fault_addl_info_add(fault, "name1", "value1");
evel_fault_addl_info_add(fault, "name2", "value2");
evel_fault_category_set(fault, "link");
/*************************************************************************/
/* Finally, post the Fault. In practice this will only ever fail if */
/* local ring-buffer is full because of event overload. */
/*************************************************************************/
evel_rc = evel_post_event((EVENT_HEADER *)fault);
if (evel_rc != EVEL_SUCCESS)
{
EVEL_ERROR("Post failed %d (%s)", evel_rc, evel_error_string());
}
}
...
```
### Event Types {#qs_event_types}
The _EVEL Library_ supports the following types of events:
1. Faults
These represent the **fault** domain in the event schema.
2. Measurements
These represent the **measurement** domain in the event schema.
3. Notification
These represent the **notification** domain in the event schema.
4. Mobile Flow
These represent the **mobileFlow** domain in the event schema.
5. Other
These represent the **other** domain in the event schema.
6. PNF Registration
These represent the **pnfRegistration** domain in the event schema.
7. SIP Signaling
These represent the **sipSignaling** domain in the event schema.
8. State Change
These represent the **stateChange** domain in the event schema.
9. Syslog
These represent the **syslog** domain in the event schema.
10. Threshold Crossing Alert
These represent the **thresholdCrossingAlert** domain in the event schema.
11. Voice Quality
These represent the **voiceQuality** domain in the event schema.
### Termination {#qs_termination}
Termination of the _EVEL Library_ is swift and brutal! Events in the buffer
at the time are "dropped on the floor" rather than waiting for the buffer to
deplete first.
```C
#include "evel.h"
...
/***************************************************************************/
/* Shutdown the library. */
/***************************************************************************/
evel_terminate();
...
```
## EVEL Adaptation {#qs_adaptation}
The _EVEL Library_ is relatively simple and should be easy to adapt into other
project environments.
### LibcURL Lifecycle
There are two circumstances where initialization of libcurl may be required:
1. If libcurl is used by the project already, and therefore already takes
responsibility of its initialization, then the libcurl initialization and
termination functions should be removed from evel_initialize() and
evel_terminate() respectively.
2. If the project is unable to satisfy the constraint that libcurl
initialization takes place in a single-threaded environment at the point
that the _EVEL Library_ can be initialized (for example, if MT code is
necessary to read the configuration parameters required for
_EVEL Library_ initialization) then it may be necessary to extract the
libcurl functions and call them separately, earlier in the program's
operation.
### Event Logging
The _EVEL Library_ uses `syslog` for logging. If this is inappropriate then
the log_debug() and log_initialize() functions should be rewritten accordingly.
**Note**: it would be a really bad idea to use the _EVEL Library_ itself for this
logging function.
[Turtles all the way down...](https://en.wikipedia.org/wiki/Turtles_all_the_way_down)
|