Browse Source

Add a stats format buffer & functions

Yann Weber 4 years ago
parent
commit
87c0efb4ba
2 changed files with 154 additions and 2 deletions
  1. 27
    1
      include/stats.h
  2. 127
    1
      src/stats.c

+ 27
- 1
include/stats.h View File

@@ -24,9 +24,12 @@
24 24
 
25 25
 #include <fcgiapp.h>
26 26
 
27
+#include <stdarg.h>
27 28
 #include <signal.h>
28 29
 #include <string.h>
29 30
 
31
+#define PYFCGI_STATS_REQS_SAMPLES (900)
32
+
30 33
 typedef struct pyfcgi_stats_s pyfcgi_stats_t;
31 34
 
32 35
 #include "conf.h"
@@ -35,7 +38,7 @@ typedef struct pyfcgi_stats_s pyfcgi_stats_t;
35 38
 struct pyfcgi_stats_s
36 39
 {
37 40
 	/**@brief Request per seconds on 15 minutes */
38
-	int reqs[900];
41
+	int reqs[PYFCGI_STATS_REQS_SAMPLES];
39 42
 	/**@brief Current request index */
40 43
 	int cur_req;
41 44
 
@@ -44,6 +47,11 @@ struct pyfcgi_stats_s
44 47
 
45 48
 	/**@brief Old SIGALRM handler */
46 49
 	struct sigaction oldact;
50
+
51
+	/**@brief Buffer to format the statistics before sending them */
52
+	char *buff;
53
+	size_t buff_ptr;
54
+	size_t buff_len;
47 55
 };
48 56
 
49 57
 /**@brief Starts collecting statistics
@@ -59,5 +67,23 @@ int pyfcgi_stats_init();
59 67
  */
60 68
 void pyfcgi_stats_collector(int);
61 69
 
70
+/**@brief Format all stats in a buffer
71
+ * @note uses the pyfcgi_stats.statsbuff buffer */
72
+size_t pyfcgi_stats_format();
73
+
74
+/**@brief Print in buffer using buff_ptr index
75
+ *@note exit on mem alloc failure
76
+ */
77
+void pyfcgi_stats_buffprintf(const char *fmt, ...);
78
+
79
+/**@brief Allocate the buffer with at least given space
80
+ * @param size_t sz the minimum buffer size
81
+ * @note allocation size is rounded
82
+ * @return 0 if OK else -1
83
+ */
84
+int pyfcgi_stats_reqbuff(size_t);
85
+
86
+const char *pyfcgi_stats_buff(const char **, size_t*);
87
+
62 88
 #endif
63 89
 

+ 127
- 1
src/stats.c View File

@@ -62,9 +62,135 @@ void pyfcgi_stats_collector(int signum)
62 62
 	{
63 63
 		stats->reqs[stats->cur_req]++;
64 64
 	}
65
-	pyfcgi_log(LOG_DEBUG, "%d req/s", stats->reqs[stats->cur_req]);
65
+	pyfcgi_log(LOG_DEBUG, "s#%d %d req/s", pyfcgi_stats.cur_req,
66
+		pyfcgi_stats.reqs[stats->cur_req]);
66 67
 	stats->cur_req++;
68
+	stats->cur_req %= PYFCGI_STATS_REQS_SAMPLES;
67 69
 
68 70
 	return;
69 71
 }
70 72
 
73
+size_t pyfcgi_stats_format()
74
+{
75
+	char uptime[80], since[80];
76
+	char ds[18], hs[5], ms[5], ss[5];
77
+	unsigned long diff, d;
78
+	short s, m, h;
79
+	struct tm *tm;
80
+
81
+	tm = localtime(&PyFCGI_conf.context.uptime);
82
+	if(!strftime(since, 80, "%F %H:%M:%S%z", tm))
83
+	{
84
+		pyfcgi_log(LOG_WARNING, "Date too long !");
85
+		strcpy(since, "???");
86
+	}
87
+	diff = (unsigned long)difftime(time(NULL), PyFCGI_conf.context.uptime);
88
+	s = diff%60;
89
+	diff /= 60;
90
+	m = diff % 60;
91
+	diff /= 60;
92
+	h = diff % 24;
93
+	diff /=24;
94
+	d = diff;
95
+	if(d) { snprintf(ds, 18, "%02ldd ", d); }
96
+	else { ds[0] = '\0'; }
97
+	if(h || *ds) { snprintf(hs, 5, "%02dh ", h); }
98
+	else { hs[0] = '\0'; }
99
+	if(m || *hs) { snprintf(ms, 5, "%02dm ", m); }
100
+	else { ms[0] = '\0'; }
101
+	if(s || *ms) { snprintf(ss, 5, "%02ds ", s); }
102
+	else { ss[0] = '\0'; }
103
+	snprintf(uptime, 80, "%s%s%s%s", ds, hs, ms, ss);
104
+	
105
+
106
+	pyfcgi_stats.buff_ptr = 0;
107
+	pyfcgi_stats_buffprintf("%s\nUptime : %s since %s\n",
108
+		PACKAGE_STRING, uptime, since);
109
+
110
+	// Request counter stats formating
111
+	double r15, r10, r5, r1, rtmp;
112
+	unsigned long stmp; // stores a 60s req sum
113
+	int i, cur_req, cur_rs, idx;
114
+	r15 = r10 = r5 = r1 = stmp = 0;
115
+	cur_req = pyfcgi_stats.cur_req;
116
+	//Block interrupt/ALARM ??
117
+	for(i=0; i<PYFCGI_STATS_REQS_SAMPLES; i++)
118
+	{
119
+		if(cur_req != pyfcgi_stats.cur_req)
120
+		{
121
+			errno = EINTR;
122
+			return 0;
123
+		}
124
+		idx = (pyfcgi_stats.cur_req - i - 1);
125
+		idx = (idx<0)?PYFCGI_STATS_REQS_SAMPLES + idx:idx;
126
+		idx %= PYFCGI_STATS_REQS_SAMPLES;
127
+		cur_rs = pyfcgi_stats.reqs[idx];
128
+		if(!i || i%60)
129
+		{
130
+			stmp += cur_rs;
131
+			continue;
132
+		}
133
+		rtmp = (long double)stmp / 60;
134
+		if(i==60) { r1 = rtmp; }
135
+		if(i<5*60) { r5 += rtmp; }
136
+		if(i<10*60) { r10 += rtmp; }
137
+		if(i<15*60) { r15 += rtmp; }
138
+		stmp = cur_rs;
139
+	}
140
+	//Restore interrupt/ALARM ??
141
+	r5 /= 5;
142
+	r10 /= 10;
143
+	r15 /= 15;
144
+	pyfcgi_stats_buffprintf("Requests stats :\n1s:%dr/s 1m:%.2fr/s 5m:%.2fr/s 10m:%.2fr/s 15m:%.2fr/s\n",
145
+		pyfcgi_stats.reqs[pyfcgi_stats.cur_req-1], r1, r5, r10, r15);
146
+	return pyfcgi_stats.buff_ptr;
147
+}
148
+
149
+void pyfcgi_stats_buffprintf(const char *fmt, ...)
150
+{
151
+	va_list ap;
152
+	size_t fsz, left;
153
+	while(1)
154
+	{
155
+		left = pyfcgi_stats.buff_len - pyfcgi_stats.buff_ptr;
156
+		va_start(ap, fmt);
157
+		fsz = vsnprintf(pyfcgi_stats.buff + pyfcgi_stats.buff_ptr,
158
+			left, fmt, ap);
159
+		va_end(ap);
160
+		if(fsz >= left)
161
+		{
162
+			if(pyfcgi_stats_reqbuff(pyfcgi_stats.buff_ptr + fsz) < 0)
163
+			{
164
+				exit(PYFCGI_ERR);
165
+			}
166
+			continue;
167
+		}
168
+		pyfcgi_stats.buff_ptr += fsz;
169
+		break;
170
+	}
171
+}
172
+
173
+int pyfcgi_stats_reqbuff(size_t sz)
174
+{
175
+	void *tmp;
176
+
177
+	if(sz <= pyfcgi_stats.buff_len) { return 0; }
178
+
179
+	sz = ((sz>>11)+1)<<11;
180
+	if( !(tmp = realloc(pyfcgi_stats.buff, sz)) )
181
+	{
182
+		pyfcgi_log(LOG_ALERT, "Unable to reallocate stats buffer : %s",
183
+			strerror(errno));
184
+		return -1;
185
+	}
186
+	pyfcgi_stats.buff_len = sz;
187
+	pyfcgi_stats.buff = tmp;
188
+	return 0;
189
+}
190
+
191
+const char *pyfcgi_stats_buff(const char **buff, size_t* len)
192
+{
193
+	*buff = pyfcgi_stats.buff;
194
+	*len = pyfcgi_stats.buff_ptr;
195
+	return *buff;
196
+}

Loading…
Cancel
Save