You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: DEVELOPER_GUIDE.md
+79-35
Original file line number
Diff line number
Diff line change
@@ -1,36 +1,44 @@
1
-
##Beginners Guide to Contributing to Fluent Bit
1
+
# Beginners Guide to Contributing to Fluent Bit
2
2
3
3
Assuming you have some basic knowledge of C, this guide should help you understand how to make code
4
4
changes to Fluent Bit.
5
5
6
-
### Table of Contents
7
-
-[Libraries](#libraries)
6
+
## Table of Contents
7
+
8
+
-[Beginners Guide to Contributing to Fluent Bit](#beginners-guide-to-contributing-to-fluent-bit)
9
+
-[Table of Contents](#table-of-contents)
10
+
-[Libraries](#libraries)
8
11
-[Memory Management](#memory-management)
9
12
-[Strings](#strings)
10
13
-[HTTP Client](#http-client)
11
14
-[Linked Lists](#linked-lists)
12
15
-[Message Pack](#message-pack)
13
-
-[Concurrency](#concurrency)
14
-
-[Plugin API](#plugin-api)
16
+
-[Concurrency](#concurrency)
17
+
-[Coroutine Code: How does it work?](#coroutine-code-how-does-it-work)
18
+
-[Practical Advice: How coroutines will affect your code](#practical-advice-how-coroutines-will-affect-your-code)
19
+
-[Filter Plugins](#filter-plugins)
20
+
-[Output plugins](#output-plugins)
21
+
-[Plugin API](#plugin-api)
15
22
-[Input](#input)
16
23
-[Filter](#filter)
17
24
-[Output](#output)
18
25
-[Config Maps](#config-maps)
19
-
-[Testing](#testing)
26
+
-[Testing](#testing)
20
27
-[Valgrind](#valgrind)
21
-
-[Need more help?](#need-more-help)
28
+
-[Need more help?](#need-more-help)
22
29
23
-
###Libraries
30
+
## Libraries
24
31
25
32
Most external libraries are embedded in the project in the [/lib](/lib) folder. To keep its footprint low and make cross-platform builds simple, Fluent Bit attempts keep its dependency graph small.
26
33
27
34
The external library you are mostly likely to interact with is [msgpack](https://github.com/msgpack/msgpack-c).
28
35
29
36
For crypto, Fluent Bit uses [mbedtls](https://github.com/ARMmbed/mbedtls).
30
37
31
-
####Memory Management
38
+
### Memory Management
32
39
33
40
When you write Fluent Bit code, you will use Fluent Bit's versions of the standard C functions for working with memory:
41
+
34
42
-[`flb_malloc()`](include/fluent-bit/flb_mem.h) - equivalent to `malloc`, allocates memory.
35
43
-[`flb_calloc()`](include/fluent-bit/flb_mem.h) - equivalent to `calloc`, allocates memory and initializes it to zero.
36
44
-[`flb_realloc()`](include/fluent-bit/flb_mem.h) - equivalent to `realloc`.
@@ -39,15 +47,16 @@ When you write Fluent Bit code, you will use Fluent Bit's versions of the standa
39
47
Note that many types have a specialized create and destroy function. For example,
40
48
[`flb_sds_create()` and `flb_sds_destroy()`](include/fluent-bit/flb_sds.h) (more about this in the next section).
41
49
42
-
####Strings
50
+
### Strings
43
51
44
52
Fluent Bit has a stripped down version of the popular [SDS](https://github.com/antirez/sds) string library. See [flb_sds.h](include/fluent-bit/flb_sds.h) for the API.
45
53
46
54
In general, you should use SDS strings in any string processing code. SDS strings are fully compatible with any C function that accepts a null-terminated sequence of characters; to understand how they work, see the [explanation on Github](https://github.com/antirez/sds#how-sds-strings-work).
47
55
48
-
####HTTP Client
56
+
### HTTP Client
49
57
50
58
Fluent Bit has its own network connection library. The key types and functions are defined in the following header files:
An `flb_upstream` structure represents a host/endpoint that you want to call. Normally, you'd store this structure somewhere so that it can be re-used. An `flb_upstream_conn` represents a connection to that host for a single HTTP request. The connection structure should not be used for more than one request.
133
142
134
-
#### Linked Lists
143
+
### Linked Lists
135
144
136
145
Fluent Bit contains a library for constructing linked lists- [mk_list](lib/monkey/include/monkey/mk_core/mk_list.h). The type stores data as a circular linked list.
137
146
@@ -190,7 +199,7 @@ static int example()
190
199
}
191
200
```
192
201
193
-
####Message Pack
202
+
### Message Pack
194
203
195
204
Fluent Bit uses [msgpack](https://msgpack.org/index.html) to internally store data. If you write code for Fluent Bit, it is almost certain that you will interact with msgpack.
Please also check out the message pack examples on the [msgpack-c GitHub repo](https://github.com/msgpack/msgpack-c).
282
291
283
-
### Concurrency
292
+
## Concurrency
284
293
285
294
Fluent Bit uses ["coroutines"](https://en.wikipedia.org/wiki/Coroutine); a concurrent programming model in which subroutines can be paused and resumed. Co-routines are cooperative routines- instead of blocking, they cooperatively pass execution between each other. Coroutines are implemented as part of Fluent Bit's core network IO libraries. When a blocking network IO operation is made (for example, waiting for a response on a socket), a routine will cooperatively yield (pause itself) and pass execution to Fluent Bit engine, which will schedule (activate) other routines. Once the blocking IO operation is complete, the sleeping coroutine will be scheduled again (resumed). This model allows Fluent Bit to achieve performance benefits without the headaches that often come from having multiple active threads.
286
295
287
296
This Fluent Bit engine consists of an event loop that is built upon [github.com/monkey/monkey](https://github.com/monkey/monkey). The monkey project is a server and library designed for low resource usage. It was primarily implemented by Eduardo Silva, who also created Fluent Bit.
288
297
289
-
#### Coroutine Code: How does it work?
298
+
### Coroutine Code: How does it work?
290
299
291
300
To understand how this works, let's walkthrough an example in the code.
292
301
293
302
The elasticsearch plugin makes an HTTP request to an elasticsearch cluster, when the following [line of code runs](https://github.com/fluent/fluent-bit/blob/1.3/plugins/out_es/es.c#L581):
303
+
294
304
```c
295
305
ret = flb_http_do(c, &b_sent);
296
306
```
297
307
298
308
This calls the http request function, in [`flb_http_client.c`, which makes a TCP write call](https://github.com/fluent/fluent-bit/blob/1.3/src/flb_http_client.c#L840):
309
+
299
310
```c
300
311
ret = flb_io_net_write(c->u_conn,
301
312
c->body_buf, c->body_len,
302
313
&bytes_body);
303
314
```
304
315
305
316
That activates code in Fluent Bit's core TCP library, which is where the coroutine magic happens. This code is in [flb_io.c](https://github.com/fluent/fluent-bit/blob/1.3/src/flb_io.c#L241). After opening a socket, the code inserts an item on the event loop:
317
+
306
318
```c
307
319
ret = mk_event_add(u->evl,
308
320
u_conn->fd,
@@ -311,6 +323,7 @@ ret = mk_event_add(u->evl,
311
323
```
312
324
313
325
This instructs the event loop to watch our socket's file descriptor. Then, [a few lines below, we yield back to the engine thread](https://github.com/fluent/fluent-bit/blob/1.3/src/flb_io.c#L304):
326
+
314
327
```c
315
328
/*
316
329
* Return the control to the parent caller, we need to wait for
Remember, only one thread is active at a time. If the current coroutine did not yield back to engine, it would monopolize execution until the socket IO operation was complete. Since IO operations may take a long time, we can increase performance by allowing another routine to perform work.
323
336
324
337
The core routine in Fluent Bit is the engine in `flb_engine.c`. Here we can find the [code that will resume the elasticsearch plugin](https://github.com/fluent/fluent-bit/blob/1.3/src/flb_engine.c#L553) once it's IO operation is complete:
338
+
325
339
```c
326
340
if (event->type == FLB_ENGINE_EV_THREAD) {
327
341
struct flb_upstream_conn *u_conn;
@@ -340,17 +354,18 @@ if (event->type == FLB_ENGINE_EV_THREAD) {
340
354
341
355
This will return execution to the code right after the [flb_thread_yield](https://github.com/fluent/fluent-bit/blob/1.3/src/flb_io.c#L304) call in the IO library.
342
356
343
-
####Practical Advice: How coroutines will affect your code
357
+
### Practical Advice: How coroutines will affect your code
344
358
345
-
#####Filter Plugins
359
+
#### Filter Plugins
346
360
347
361
Filter plugins do not support coroutines, consequently you must disable async mode if your filter makes an HTTP request:
362
+
348
363
```c
349
364
/* Remove async flag from upstream */
350
365
upstream->flags &= ~(FLB_IO_ASYNC);
351
366
```
352
367
353
-
#####Output plugins
368
+
#### Output plugins
354
369
355
370
Output plugins use coroutines. Plugins have a context structure which is available in all calls and can be used to store state. In general, you can write code without ever considering concurrency. This is because only one coroutine is active at a time. Thus, synchronization primitives like mutex locks or semaphores are not needed.
356
371
@@ -393,18 +408,17 @@ This can be re-enabled at any time:
393
408
upstream->flags |= FLB_IO_ASYNC;
394
409
```
395
410
396
-
397
-
### Plugin API
411
+
## Plugin API
398
412
399
413
Each plugin is a shared object which is [loaded into Fluent Bit](https://github.com/fluent/fluent-bit/blob/1.3/src/flb_plugin.c#L70) using dlopen and dlsym.
400
414
401
-
####Input
415
+
### Input
402
416
403
417
The input plugin structure is defined in [flb_input.h](https://github.com/fluent/fluent-bit/blob/master/include/fluent-bit/flb_input.h#L62). There are a number of functions which a plugin can implement, most only implement `cb_init`, `cb_collect`, and `cb_exit`.
404
418
405
419
The [`"dummy"` input plugin](plugins/in_dummy) very simple and is an excellent example to review to understand more.
406
420
407
-
####Filter
421
+
### Filter
408
422
409
423
The structure for filter plugins is defined in [flb_filter.h](https://github.com/fluent/fluent-bit/blob/master/include/fluent-bit/flb_filter.h#L44). Each plugin must implement `cb_init`, `cb_filter`, and `cb_exit`.
410
424
@@ -417,13 +431,13 @@ Note that filter plugins can not asynchronously make HTTP requests. If your plug
417
431
upstream->flags &= ~(FLB_IO_ASYNC);
418
432
```
419
433
420
-
####Output
434
+
### Output
421
435
422
436
Output plugins are defined in [flb_output.h](https://github.com/fluent/fluent-bit/blob/master/include/fluent-bit/flb_output.h#L57). Each plugin must implement `cb_init`, `cb_flush`, and `cb_exit`.
423
437
424
438
The [stdout plugin](plugins/out_stdout) is very simple; review its code to understand how output plugins work.
425
439
426
-
####Config Maps
440
+
### Config Maps
427
441
428
442
Config maps are an improvement to the previous Fluent Bit API that was used by plugins to read configuration values. The new config maps feature warns the user if there is an unknown configuration key and reduces risk of bad configuration due to typos or deprecated property names. They will also allow dynamic configuration reloading to be implemented in the future.
In the above code snippet, the property *format* is of type string which supports formats like json, msgpack etc. It has default value NULL(in which case it uses msgpack), no flags, and it is being only validated by the config map and hence set_property field is `FLB_FALSE` with member offset 0. No description is written for *format* property at present.
492
507
Similarly, for the property *json_date_key*, type is string, default value is date, and it is being written to context so the set_property field is `FLB_TRUE` with a member offset. Again, no description is written for it.
493
508
494
-
495
509
Upon initilization the engine loads the config map like [this](https://github.com/fluent/fluent-bit/blob/v1.4.2/plugins/out_stdout/stdout.c#L48):
496
510
497
511
```c
@@ -501,23 +515,53 @@ Upon initilization the engine loads the config map like [this](https://github.co
501
515
[flb_output_config_map_set](https://github.com/fluent/fluent-bit/blob/v1.4.2/include/fluent-bit/flb_output.h#L510) returns [flb_config_map_set](https://github.com/fluent/fluent-bit/blob/v1.4.2/src/flb_config_map.c#L513) which is a function used by plugins that needs to populate their context structure with the configuration properties already mapped.
502
516
503
517
Some points to keep in mind while migrating an existing plugin to a config map interface:
518
+
504
519
- All memory allocations and releases of properties on exit are handled by the config map interface.
505
520
- The config map does not parse host and port properties since these properties are handled automatically for plugins that perform network operations.
506
521
- Some plugins might also have an empty config_map. This is so that it would show an error when someone tried to use a non-existent parameter.
507
522
508
-
###Testing
523
+
## Testing
509
524
510
525
During development, you can build Fluent Bit as follows:
511
526
512
-
```
527
+
```shell
513
528
cd build
514
529
cmake -DFLB_DEV=On ../
515
530
make
516
531
```
532
+
517
533
Note that Fluent Bit uses Cmake 3 and on some systems you may need to invoke it as `cmake3`.
518
534
519
-
To enable the unit tests run:
535
+
To set up and build your environment, please refer to the packaging containers for a dependency list: <https://github.com/fluent/fluent-bit/tree/master/packaging/distros>.
536
+
537
+
A [`Vagrantfile`](./Vagrantfile) is provided to simplify building on a VM, this will set up a VM using Vagrant you can then build in.
538
+
539
+
```shell
540
+
vagrant up
541
+
vagrant ssh
542
+
cd build
543
+
rm -rf *
544
+
cmake ...
545
+
make
546
+
```
547
+
548
+
Be aware of any permissions issues with the filesystem on the VM vs the host.
549
+
You may prefer to build to an un-exposed filesystem:
550
+
551
+
```shell
552
+
vagrant up
553
+
vagrant ssh
554
+
mkdir -p /tmp/build
555
+
cd /tmp/build
556
+
cmake ... /vagrant
557
+
make
520
558
```
559
+
560
+
It also acts as a reference for the tooling required to be installed on a local PC if you want to build things.
@@ -526,31 +570,31 @@ Internal tests are for the internal libraries of Fluent Bit. Runtime tests are f
526
570
527
571
You can run the unit tests with `make test`, however, this is inconvenient in practice. Each test file will create an executable in the `build/bin` directory which you can run directly. For example, if you want to run the SDS tests, you can invoke them as follows:
528
572
529
-
```
573
+
```shell
530
574
$ ./bin/flb-it-sds
531
575
Test sds_usage... [ OK ]
532
576
Test sds_printf... [ OK ]
533
577
SUCCESS: All unit tests have passed.
534
578
```
535
579
536
-
####Valgrind
580
+
### Valgrind
537
581
538
582
[Valgrind](https://valgrind.org/) is a tool that will help you detect and diagnose memory issues in your code. It will check for memory leaks and invalid memory accesses.
539
583
540
584
To use it while developing, invoke it before Fluent Bit:
541
585
542
-
```
586
+
```shell
543
587
valgrind ./bin/fluent-bit {args for fluent bit}
544
588
```
545
589
546
590
Valgrind becomes especially powerful when you run it on your unit tests. We recommend writing unit tests that cover a large fraction of code paths in your contribution. You can then check your code for memory issues by invoking the test binaries with Valgrind:
547
591
548
-
```
549
-
$ valgrind ./bin/flb-rt-your-test
592
+
```shell
593
+
valgrind ./bin/flb-rt-your-test
550
594
```
551
595
552
596
This will allow you to check for memory issues in code paths (ex error cases) which are hard to trigger through manual testing.
553
597
554
-
###Need more help?
598
+
## Need more help?
555
599
556
600
The best way to learn how Fluent Bit code works is to read it. If you need help understanding the code, reach out to the community, or open a PR with changes that are a work in progress.
0 commit comments