/
logger.h
178 lines (159 loc) · 8.03 KB
/
logger.h
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
/*! \file logger.h
* \author Lorenzo Miniero <lorenzo@meetecho.com>
* \copyright GNU General Public License v3
* \brief Modular Janus loggers (headers)
* \details This header contains the definition of the callbacks all
* the custom loggers need to implement to interact with the Janus core.
* In fact, a custom logger is basically a module that receives log lines
* from the Janus core and plugins, so that they can be handled somehow
* (e.g., aggregated or forwarded elsewhere).
*
* An logger plugin that wants to register at the Janus core needs to
* implement the \c janus_logger interface. This includes callbacks
* the Janus core can use to receive log lines to process. Besides, as a
* logger plugin is a shared object, and as such external to the
* core itself, in order to be dynamically loaded at startup it needs
* to implement the \c create_l() hook as well, that should return a
* pointer to the plugin instance. This is an example of such a step:
*
\verbatim
static janus_logger mylogger = {
[..]
};
janus_logger *create(void) {
JANUS_LOG(LOG_VERB, , "%s created!\n", MY_LOGGER_NAME);
return &mylogger;
}
\endverbatim
*
* This will make sure that your logger plugin is loaded at startup
* by the Janus core, if it is deployed in the proper folder.
*
* As anticipated and described in the above example, a logger plugin
* must basically be an instance of the \c janus_logger type. As such,
* it must implement the following methods and callbacks for the core:
*
* - \c init(): this is called by the Janus core as soon as your logger
* plugin is started; this is where you should setup your logger plugin
* (e.g., static stuff and reading the configuration file);
* - \c destroy(): on the other hand, this is called by the core when it
* is shutting down, and your logger plugin should too;
* - \c get_api_compatibility(): this method MUST return JANUS_LOGGER_API_VERSION;
* - \c get_version(): this method should return a numeric version identifier (e.g., 3);
* - \c get_version_string(): this method should return a verbose version identifier (e.g., "v1.0.1");
* - \c get_description(): this method should return a verbose description of your logger plugin (e.g., "This is a logger that saves log lines on a database");
* - \c get_name(): this method should return a short display name for your logger plugin (e.g., "My Amazing Logger");
* - \c get_package(): this method should return a unique package identifier for your logger plugin (e.g., "janus.logger.mylogger");
* - \c incoming_logline(): this callback informs the logger that a log line is available for consumption.
*
* All the above methods and callbacks are mandatory: the Janus core will
* reject al logger plugin that doesn't implement any of the mandatory callbacks.
*
* Unlike other kind of modules (transports, plugins), the \c init() method
* here only passes the path to the configurations files folder, as loggers
* never need to contact the Janus core themselves. This path can be used to
* read and parse a configuration file for the logger plugin: the logger
* plugins we made available out of the box use the package name as a
* name for the file (e.g., \c janus.logger.json.jcfg for the sample
* logger plugin), but you're free to use a different one, as long
* as it doesn't collide with existing ones. Besides, the existing logger
* plugins use the same libconfig format for configuration files the core
* uses (relying on the \c janus_config helpers for the purpose) but
* again, if you prefer a different format (XML, JSON, etc.) that's up to you.
*
* \ingroup loggerapi
* \ref loggerapi
*/
#ifndef JANUS_LOGGER_H
#define JANUS_LOGGER_H
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <inttypes.h>
#include <glib.h>
#include <jansson.h>
#include "../utils.h"
/*! \brief Version of the API, to match the one logger plugins were compiled against */
#define JANUS_LOGGER_API_VERSION 3
/*! \brief Initialization of all logger plugin properties to NULL
*
* \note All logger plugins MUST add this as the FIRST line when initializing
* their logger plugin structure, e.g.:
*
\verbatim
static janus_logger janus_fake_logger_plugin =
{
JANUS_LOGGER_INIT,
.init = janus_fake_init,
[..]
\endverbatim
*/
#define JANUS_LOGGER_INIT(...) { \
.init = NULL, \
.destroy = NULL, \
.get_api_compatibility = NULL, \
.get_version = NULL, \
.get_version_string = NULL, \
.get_description = NULL, \
.get_name = NULL, \
.get_author = NULL, \
.get_package = NULL, \
.incoming_logline = NULL, \
## __VA_ARGS__ }
/*! \brief The logger plugin session and callbacks interface */
typedef struct janus_logger janus_logger;
/*! \brief The logger plugin session and callbacks interface */
struct janus_logger {
/*! \brief Logger plugin initialization/constructor
* @param[in] server_name Name of the Janus instance generating the logs
* @param[in] config_path Path of the folder where the configuration for this logger plugin can be found
* @returns 0 in case of success, a negative integer in case of error */
int (* const init)(const char *server_name, const char *config_path);
/*! \brief Logger plugin deinitialization/destructor */
void (* const destroy)(void);
/*! \brief Informative method to request the API version this logger plugin was compiled against
* \note All logger plugins MUST implement this method and return JANUS_LOGGER_API_VERSION
* to make this work, or they will be rejected by the core. */
int (* const get_api_compatibility)(void);
/*! \brief Informative method to request the numeric version of the logger plugin */
int (* const get_version)(void);
/*! \brief Informative method to request the string version of the logger plugin */
const char *(* const get_version_string)(void);
/*! \brief Informative method to request a description of the logger plugin */
const char *(* const get_description)(void);
/*! \brief Informative method to request the name of the logger plugin */
const char *(* const get_name)(void);
/*! \brief Informative method to request the author of the logger plugin */
const char *(* const get_author)(void);
/*! \brief Informative method to request the package name of the logger plugin (what will be used in web applications to refer to it) */
const char *(* const get_package)(void);
/*! \brief Method to notify the logger plugin that a new log line is available
* \details All log lines are notified as a string
* \note Do NOT handle the log line directly in this method. Janus sends
* log lines from its internal logger thread, so any I/O or blocking thing
* you may be doing here would most likely end up slowing it down. Just take
* note of it and handle it somewhere else. It's your responsibility to
* duplicate the string to use it later: the string you get in the callback
* is NOT a copy, and MUST NOT be modified.
* @param[in] timestamp Monotonic timestamp of when the log line was printed
* @param[in] line String containing the log line */
void (* const incoming_logline)(int64_t timestamp, const char *line);
/*! \brief Method to send a request to this specific logger plugin
* \details The method takes a Jansson json_t, that contains all the info related
* to the request. This object will come from an Admin API request, and is
* meant to represent a synchronous request. Since each logger can have
* its own bells and whistles, there's no constraint on what this object should
* contain, which is entirely logger-specific. A json_t object needs to be
* returned as a response, which will be sent in response to the Admin API call.
* This can be useful to tweak settings in real-time, or to probe the internals
* of the logger plugin for monitoring purposes.
* @param[in] request Jansson object containing the request
* @returns A Jansson object containing the response for the client */
json_t *(* const handle_request)(json_t *request);
};
/*! \brief The hook that logger plugins need to implement to be created from the Janus core */
typedef janus_logger* create_l(void);
#endif