Browse Source

Starts logger & conf

Yann Weber 4 years ago
parent
commit
0050577e45
3 changed files with 455 additions and 0 deletions
  1. 83
    0
      src/conf.h
  2. 204
    0
      src/logger.c
  3. 168
    0
      src/logger.h

+ 83
- 0
src/conf.h View File

@@ -0,0 +1,83 @@
1
+/*
2
+ * Copyright (C) 2019 Weber Yann
3
+ * 
4
+ * This file is part of PyFCGI.
5
+ * 
6
+ * PyFCGI is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU Affero General Public License as published by
8
+ * the Free Software Foundation, either version 3 of the License, or
9
+ * any later version.
10
+ * 
11
+ * PyFCGI is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ * GNU Affero General Public License for more details.
15
+ * 
16
+ * You should have received a copy of the GNU Affero General Public License
17
+ * along with PyFCGI.  If not, see <http://www.gnu.org/licenses/>.
18
+ */
19
+#ifndef __CONF_H___
20
+#define __CONF_H___
21
+
22
+#include "config.h"
23
+/**@defgroup conf_internal PYFCGI configuration handling
24
+ */
25
+/**@defgroup conf_glob PYFCGI global (for all process) configurations
26
+ * @see struct_pyfcgi_conf_s
27
+ * @ingroup conf_internal */
28
+
29
+/**@defgroup ret_status Function & process return status
30
+ */
31
+#define PYFCGI_ERR 16
32
+/**@ingroup ret_status */
33
+#define PYFCGI_WORKER_FAIL 32
34
+/**@ingroup ret_status */
35
+#define PYFCGI_MASTER_FAIL 64
36
+/**@ingroup ret_status */
37
+#define PYFCGI_FATAL 128
38
+
39
+/**@brief Friendly name for @ref struct pyfcgi_conf_s
40
+ * @see struct pyfcgi_conf_s */
41
+typedef struct pyfcgi_conf_s pyfcgi_conf_t;
42
+typedef struct pyfcgi_conf_logger_s pyfcgi_conf_logger_t;
43
+typedef struct pyfcgi_context_s pyfcgi_context_t;
44
+
45
+struct pyfcgi_context_s {
46
+	int foo;
47
+};
48
+
49
+/**@brief Structure containing configuration
50
+ * @ingroup conf_internal
51
+ * The structure is used for the global @ref pyfcgi_conf variable.
52
+ * @see pyfcgi_conf_t
53
+ */
54
+struct pyfcgi_conf_s
55
+{
56
+	/**@brief Entrypoint module name
57
+	 * @ingroup conf_glob */
58
+	char *py_entrymod;
59
+	/**@brief Entrypoint function name
60
+	 * @ingroup conf_glob */
61
+	char *py_entryfun;
62
+	/**@brief Minimum count worker in pool
63
+	 * @ingroup conf_glob */
64
+	int min_wrk;
65
+	/**@brief Maximum count workers in pool
66
+	 * @ingroup conf_glob */
67
+	int max_wrk;
68
+	/**@brief Maximum request before a worker restarts (0 for no restart)
69
+	 * @ingroup conf_glob */
70
+	int max_reqs;
71
+
72
+	/**@brief Logger configuration
73
+	 * @ingroupe conf_glob */
74
+	pyfcgi_conf_logger_t logs;
75
+
76
+	pyfcgi_context_t context;
77
+};
78
+
79
+
80
+/**@brief Configuration globals, inherited from parent to childs */
81
+pyfcgi_conf_t PyFCGI_conf;
82
+
83
+#endif

+ 204
- 0
src/logger.c View File

@@ -0,0 +1,204 @@
1
+#include "logger.h"
2
+
3
+int pyfcgi_logger_add(const char *filename, logmask_t loglvl, logmask_t logtyp,
4
+                      const char *format)
5
+{
6
+	pyfcgi_conf_logger_t *conf;
7
+	pyfcgi_logger_t logger;
8
+	size_t new_idx;
9
+	void *tmp;
10
+	int err;
11
+	char *err_fmt;
12
+
13
+	conf = &PyFCGI_conf.logs;
14
+
15
+	if(conf->logger_sz == 255)
16
+	{
17
+		pyfcgi_log(LOG_ERR, "Maximum of 255 logger reached, unable to add this one...");
18
+		return PYFCGI_ERR;
19
+	}
20
+
21
+	if(pyfcgi_logger_add_format(format, &(logger.fmt_id)))
22
+	{
23
+		return PYFCGI_FATAL;
24
+	}
25
+	if(!logger.filename)
26
+	{
27
+		err_fmt = "Unable to duplicate logger filename : %s";
28
+		goto err;
29
+	}
30
+
31
+	logger.loglvl = loglvl;
32
+	logger.logtyp = logtyp;
33
+	logger.filename = strdup(filename);
34
+
35
+	new_idx = conf->logger_sz;
36
+	conf->logger_sz++;
37
+	if( !(tmp = realloc(conf->loggers,
38
+	                    sizeof(pyfcgi_logger_t) * conf->logger_sz)) )
39
+	{
40
+		err = errno;
41
+		err_fmt = "Unable to realloc loggers array : %s";
42
+		goto err_free_filename;
43
+	}
44
+	conf->loggers[new_idx] = logger;
45
+	return 0;
46
+
47
+err_free_filename:
48
+	free(logger.filename);
49
+err:
50
+	pyfcgi_log(LOG_ALERT,
51
+	           err_fmt,
52
+		   strerror(err));
53
+	return PYFCGI_FATAL;	
54
+}
55
+
56
+int pyfcgi_logger_add_format(const char* format, size_t* idx)
57
+{
58
+	char *fmt;
59
+	size_t i;
60
+	void *tmp;
61
+	pyfcgi_conf_logger_t *conf;
62
+
63
+	conf = &PyFCGI_conf.logs;
64
+
65
+	for(i=0; i<conf->format_sz; i++)
66
+	{
67
+		if(!strcmp(format, conf->format[i])) { break; }
68
+	}
69
+	if(idx) { *idx = i; }
70
+	if( i<conf->format_sz )
71
+	{
72
+		return 0;
73
+	}
74
+	if( !(fmt = strdup(format)) )
75
+	{
76
+		pyfcgi_log(LOG_ALERT, "Fails to strdup new format : %s",
77
+			   strerror(errno));
78
+		return PYFCGI_FATAL;
79
+	}
80
+	conf->format_sz++;
81
+	if( !(tmp = realloc(conf->format,
82
+	                    sizeof(char*) * conf->format_sz)) )
83
+	{
84
+		conf->format_sz--;
85
+		pyfcgi_log(LOG_ALERT, "Fails to realloc logger format array : %s",
86
+			   strerror(errno));
87
+		return PYFCGI_FATAL;
88
+	}
89
+	conf->format[i] = fmt;
90
+	return 0;
91
+}
92
+
93
+int pyfcgi_logger_open(pyfcgi_logger_t *logger)
94
+{
95
+	if( (logger->fd = open(logger->filename,
96
+	                       O_WRONLY | O_APPEND | O_CREAT, 00640) < 0) )
97
+	{
98
+		pyfcgi_log(LOG_ERR,
99
+		           "Unable to open log file '%s' : %s",
100
+			   strerror(errno));
101
+		return PYFCGI_ERR;
102
+	}
103
+	return 0;
104
+}
105
+
106
+int pyfcgi_log(loglvl_t lvl, const char *fmt, ...)
107
+{
108
+	int ret;
109
+	va_list ap;
110
+	va_start(ap, fmt);
111
+	ret = vpyfcgi_log(lvl, fmt, ap);
112
+	va_end(ap);
113
+	return ret;
114
+}
115
+
116
+int vpyfcgi_log(loglvl_t lvl, const char *fmt, va_list ap)
117
+{
118
+	int len, ret;
119
+	pyfcgi_conf_logger_t *conf;
120
+	unsigned char i;
121
+	char buf[512];
122
+
123
+	conf = &PyFCGI_conf.logs;
124
+
125
+	if(conf->flags & PYFCGI_LOG_FSYSLOG)
126
+	{
127
+		vsyslog(SYSLOG_LVLS[(lvl & 0xF0) >> 4], fmt, ap);
128
+	}
129
+
130
+	len = 0;
131
+	if(conf->format_sz > 1)
132
+	{
133
+		len = vdprintf(conf->pipes[1], fmt, ap);
134
+		if(len < 0)
135
+		{
136
+			if(conf->flags & PYFCGI_LOG_FSYSLOG)
137
+			{
138
+				syslog(SYSLOG_ALERT, 
139
+				       "Unable to write to multiplexer pipe when trying to log : %s",
140
+				       strerror(errno));
141
+			}
142
+			return PYFCGI_FATAL;
143
+		}
144
+	}
145
+	else if (conf->format_sz)
146
+	{
147
+		len = vdprintf(conf->loggers[0].fd, fmt, ap);
148
+		if(len < 0)
149
+		{
150
+			if(conf->flags & PYFCGI_LOG_FSYSLOG)
151
+			{
152
+				syslog(SYSLOG_ALERT, 
153
+				       "Unable to write to single FD to '%s' when trying to log : %s",
154
+				       conf->loggers[0].filename, strerror(errno));
155
+			}
156
+			return PYFCGI_FATAL;
157
+		}
158
+		return 0;
159
+	}
160
+	for(i=0; i<conf->logger_sz-1; i++)
161
+	{
162
+		ret = tee(conf->pipes[0], conf->loggers[i].fd, len, 0);
163
+		if(ret < 0)
164
+		{
165
+			if(conf->flags & PYFCGI_LOG_FSYSLOG)
166
+			{
167
+				syslog(SYSLOG_ALERT, 
168
+				       "Unable to splice to last logfile '%s' : %s",
169
+				       conf->loggers[i].filename, strerror(errno));
170
+			}
171
+			return PYFCGI_FATAL;
172
+		}
173
+	}
174
+	ret = splice(conf->pipes[0], NULL, conf->loggers[i].fd, NULL, len, 0);
175
+	if(ret < 0)
176
+	{
177
+		if(conf->flags & PYFCGI_LOG_FSYSLOG)
178
+		{
179
+			syslog(SYSLOG_ALERT, 
180
+			       "Unable to splice to last logfile '%s' : %s",
181
+			       conf->loggers[i].filename, strerror(errno));
182
+		}
183
+		return PYFCGI_ERR;
184
+	}
185
+	if(ret < len)
186
+	{
187
+		if(conf->flags & PYFCGI_LOG_FSYSLOG)
188
+		{
189
+			syslog(SYSLOG_WARNING, 
190
+			       "Unable to splice all data to logfile. Flushing pipe.");
191
+		}
192
+
193
+		do
194
+		{
195
+			len -= (ret<len)?ret:len;
196
+			ret = read(conf->pipes[0], buf, len>512?512:len);
197
+			if(ret < 0)
198
+			{
199
+				return PYFCGI_ERR;
200
+			}
201
+		}while(len);
202
+	}
203
+	return 0;
204
+}

+ 168
- 0
src/logger.h View File

@@ -0,0 +1,168 @@
1
+/*
2
+ * Copyright (C) 2019 Weber Yann
3
+ * 
4
+ * This file is part of PyFCGI.
5
+ * 
6
+ * PyFCGI is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU Affero General Public License as published by
8
+ * the Free Software Foundation, either version 3 of the License, or
9
+ * any later version.
10
+ * 
11
+ * PyFCGI is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ * GNU Affero General Public License for more details.
15
+ * 
16
+ * You should have received a copy of the GNU Affero General Public License
17
+ * along with PyFCGI.  If not, see <http://www.gnu.org/licenses/>.
18
+ */
19
+#ifndef __LOGGER_H___
20
+#define __LOGGER_H___
21
+
22
+#include "config.h"
23
+#include <syslog.h>
24
+#include <stdlib.h>
25
+#include <errno.h>
26
+#include <string.h>
27
+#include <stdarg.h>
28
+#include <unistd.h>
29
+#include <fcntl.h>
30
+#include <stdio.h>
31
+#include <sys/types.h>
32
+#include <sys/stat.h>
33
+
34
+/**@defgroup conf_logger Logging configuration
35
+ * @ingroup conf_internal
36
+ */
37
+
38
+/**@defgroup log_facility Logger custom facilities */
39
+/**@ingroup log_facility */
40
+#define LOG_GLOBAL 0
41
+/**@ingroup log_facility */
42
+#define LOG_ACCESS 1
43
+/**@ingroup log_facility */
44
+#define LOG_INTERN 2
45
+/**@ingroup log_facility */
46
+#define LOG_WORKER 4
47
+/**@ingroup log_facility */
48
+#define LOG_MASTER 8
49
+
50
+#define SYSLOG_EMERG   LOG_EMERG
51
+#define SYSLOG_ALERT   LOG_ALERT
52
+#define SYSLOG_CRIT    LOG_CRIT
53
+#define SYSLOG_ERR     LOG_ERR
54
+#define SYSLOG_WARNING LOG_WARNING
55
+#define SYSLOG_NOTICE  LOG_NOTICE
56
+#define SYSLOG_INFO    LOG_INFO
57
+#define SYSLOG_DEBUG   LOG_DEBUG
58
+const short SYSLOG_LVLS[8] = {LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR,
59
+                              LOG_WARNING, LOG_NOTICE, LOG_INFO, LOG_DEBUG};
60
+
61
+#undef LOG_EMERG
62
+#undef LOG_ALERT
63
+#undef LOG_CRIT
64
+#undef LOG_ERR
65
+#undef LOG_WARNING
66
+#undef LOG_NOTICE
67
+#undef LOG_INFO
68
+#undef LOG_DEBUG
69
+
70
+/* This way we can mimic syslog and the or'ed level | facility */
71
+//#define LOG_EMERG (1 << 4)
72
+#define LOG_EMERG (2 << 4)
73
+#define LOG_ALERT (2 << 4)
74
+#define LOG_CRIT (3 << 4)
75
+#define LOG_ERR (4 << 4)
76
+#define LOG_WARNING (5 << 4)
77
+#define LOG_NOTICE (6 << 4)
78
+#define LOG_INFO (7 << 4)
79
+#define LOG_DEBUG (8 << 4)
80
+
81
+/**@defgroup conf_logger_flags Logger confifurations flags
82
+ * @ingroup conf_logger */
83
+/**@ingroup cong_logger_flags */
84
+#define PYFCGI_LOG_FSYSLOG 1
85
+/**@brief Indicate if the logger should try to reopen on failure
86
+ * @ingroup cong_logger_flags */
87
+#define PYFCGI_LOG_FRETRY 2
88
+/**@brief Exit if failure
89
+ * @ingroup cong_logger_flags */
90
+#define PYFCG_LOG_FEXIT_ONFAIL 4
91
+
92
+/**@brief Log level mask
93
+ * @ingroup conf_logger
94
+ * Allow selection of loglevels using a bitwise mask 1 << LEVEL
95
+ */
96
+typedef unsigned char logmask_t;
97
+typedef unsigned char loglvl_t;
98
+typedef struct pyfcgi_logger_s pyfcgi_logger_t;
99
+
100
+/**@brief Logger configuration
101
+ * @ingroup conf_logger
102
+ */
103
+struct pyfcgi_conf_logger_s
104
+{
105
+	/**@brief Or combination of @ref PYFCGI_LOG_SYSLOG or
106
+	 * @ref PYFCGI_LOG_RETRY */
107
+	short flags;
108
+	char *syslog_ident;
109
+	int syslog_facility;
110
+	logmask_t syslog_loglvl;
111
+	logmask_t syslog_logtyp;
112
+
113
+	/**@brief PyFCGI internal ident, prefixes all log messages */
114
+	char *ident;
115
+	logmask_t facility;
116
+
117
+	pyfcgi_logger_t *loggers;
118
+	unsigned char logger_sz;
119
+
120
+	char **format;
121
+	unsigned char format_sz;
122
+
123
+	/**@brief Internal pipe to tee(2) the message on loggers */
124
+	int pipes[2];
125
+};
126
+
127
+/**@brief Informations on a logger
128
+ * @ingroup conf_logger
129
+ */
130
+struct pyfcgi_logger_s
131
+{
132
+	char *filename;
133
+	int fd;
134
+	logmask_t loglvl;
135
+	logmask_t logtyp;
136
+
137
+	size_t fmt_id;
138
+};
139
+
140
+#include "conf.h"
141
+
142
+/**@brief Add a new logger
143
+ * @param char* filename
144
+ * @param logmask_t loglvl a mask indicating wich loglevels should be logged
145
+ * @param logmask_t typemask a mask indicating wich facility should be logged
146
+ * @param char* log format (or NULL for default format)
147
+ */
148
+int pyfcgi_logger_add(const char*, logmask_t, logmask_t, const char*);
149
+
150
+/**@brief Add a new format
151
+ * @param char *format
152
+ * @param size_t* idx if not NULL, will contain the format index
153
+ * @return 0 if OK
154
+ */
155
+int pyfcgi_logger_add_format(const char*, size_t*);
156
+
157
+/**@brief Open a logger
158
+ * @param pyfcgi_logger_t*
159
+ * @return 0 if no errors
160
+ */
161
+int pyfcgi_logger_open(pyfcgi_logger_t*);
162
+
163
+int pyfcgi_logger_set_ident(const char*);
164
+
165
+int pyfcgi_log(loglvl_t, const char*, ...);
166
+int vpyfcgi_log(loglvl_t, const char*, va_list);
167
+
168
+#endif

Loading…
Cancel
Save