1 #include <uwsgi.h>
2
3 extern struct uwsgi_server uwsgi;
4
5 struct uwsgi_redislog_state {
6 int fd;
7 char *password;
8 char *address;
9 char *id;
10 char *command;
11 char *prefix;
12 char msgsize[11];
13 struct iovec iovec[7];
14 char response[8];
15 };
16
uwsgi_redis_logger_build_command(char * src)17 static char *uwsgi_redis_logger_build_command(char *src) {
18 ssize_t len = 4096;
19 char *dst = uwsgi_calloc(len);
20 char *orig_dst = dst;
21 int count = 2;
22 char *ptr = src;
23
24 // first of all, count the number of spaces
25 while(*ptr++) { if (*ptr == ' ') count++; }
26
27 int pos = snprintf(dst, 4096, "*%d\r\n", count);
28 dst+=pos;
29 len -= pos;
30
31 ptr = src;
32 char *base = src;
33
34 while(*ptr++) {
35 if (*ptr == ' ') {
36 pos = snprintf(dst, len, "$%d\r\n%.*s\r\n", (int) (ptr-base), (int) (ptr-base), base);
37 if (pos >= len || pos < 0) {
38 // i do not know what to do, better to exit...
39 exit(1);
40 }
41 base = ptr+1;
42 dst+=pos;
43 len-= pos;
44 }
45 }
46
47 pos = snprintf(dst, len, "$%d\r\n%.*s\r\n", (int) ((ptr-1)-base), (int) ((ptr-1)-base), base);
48 if (pos > len || pos < 0) {
49 // i do not know what to do, better to exit...
50 exit(1);
51 }
52 return orig_dst;
53 }
54
uwsgi_redis_logger_discard_response(struct uwsgi_redislog_state * uredislog)55 static ssize_t uwsgi_redis_logger_discard_response(struct uwsgi_redislog_state *uredislog) {
56 ssize_t ret = 0, ret2;
57 again:
58 // read til a \n is found (ugly but fast)
59 ret2 = read(uredislog->fd, uredislog->response, 8);
60 if (ret2 <= 0) {
61 close(uredislog->fd);
62 uredislog->fd = -1;
63 return -1;
64 }
65 ret += ret2;
66 if (!memchr(uredislog->response, '\n', ret2)) {
67 goto again;
68 }
69 return ret;
70 }
71
uwsgi_redis_logger(struct uwsgi_logger * ul,char * message,size_t len)72 ssize_t uwsgi_redis_logger(struct uwsgi_logger *ul, char *message, size_t len) {
73
74 ssize_t ret;
75 struct uwsgi_redislog_state *uredislog = NULL;
76
77 if (!ul->configured) {
78
79 if (!ul->data) {
80 ul->data = uwsgi_calloc(sizeof(struct uwsgi_redislog_state));
81 uredislog = (struct uwsgi_redislog_state *) ul->data;
82 }
83
84 if (ul->arg != NULL) {
85 char *logarg = uwsgi_str(ul->arg);
86 char *at = strchr(logarg, '@');
87 if (at) {
88 *at = 0;
89 uredislog->password = logarg;
90 logarg = at + 1;
91 }
92 char *comma1 = strchr(logarg, ',');
93 if (!comma1) {
94 char *slash = strchr(logarg, '/');
95 if (slash) {
96 *slash = 0;
97 uredislog->id = slash + 1;
98 }
99 uredislog->address = uwsgi_resolve_ip(logarg);
100 goto done;
101 }
102 *comma1 = 0;
103 char *slash = strchr(logarg, '/');
104 if (slash) {
105 *slash = 0;
106 uredislog->id = slash + 1;
107 }
108 uredislog->address = logarg;
109 comma1++;
110 if (*comma1 == 0) goto done;
111
112 char *comma2 = strchr(comma1,',');
113 if (!comma2) {
114 uredislog->command = uwsgi_redis_logger_build_command(comma1);
115 goto done;
116 }
117
118 *comma2 = 0;
119 uredislog->command = uwsgi_redis_logger_build_command(comma1);
120 comma2++;
121 if (*comma2 == 0) goto done;
122
123 uredislog->prefix = comma2;
124 }
125
126 done:
127
128 if (!uredislog->password) uredislog->password = NULL;
129 if (!uredislog->id) uredislog->id = "0";
130 if (!uredislog->address) uredislog->address = uwsgi_str("127.0.0.1:6379");
131 if (!uredislog->command) uredislog->command = "*3\r\n$7\r\npublish\r\n$5\r\nuwsgi\r\n";
132 if (!uredislog->prefix) uredislog->prefix = "";
133
134 uredislog->fd = -1;
135
136 uredislog->iovec[0].iov_base = uredislog->command;
137 uredislog->iovec[0].iov_len = strlen(uredislog->command);
138 uredislog->iovec[1].iov_base = "$";
139 uredislog->iovec[1].iov_len = 1;
140
141 uredislog->iovec[2].iov_base = uredislog->msgsize;
142
143 uredislog->iovec[3].iov_base = "\r\n";
144 uredislog->iovec[3].iov_len = 2;
145
146 uredislog->iovec[4].iov_base = uredislog->prefix;
147 uredislog->iovec[4].iov_len = strlen(uredislog->prefix);
148
149 uredislog->iovec[6].iov_base = "\r\n";
150 uredislog->iovec[6].iov_len = 2;
151
152 ul->configured = 1;
153 }
154
155 uredislog = (struct uwsgi_redislog_state *) ul->data;
156 if (uredislog->fd == -1) {
157 struct iovec setup_iov;
158 char setup_buf[4096];
159 uredislog->fd = uwsgi_connect(uredislog->address, uwsgi.socket_timeout, 0);
160 if (uredislog->password) {
161 setup_iov.iov_len = snprintf(
162 setup_buf, sizeof (setup_buf), "*2\r\n$4\r\nauth\r\n$%zu\r\n%*s\r\n",
163 strlen(uredislog->password), (int)strlen(uredislog->password), uredislog->password);
164 setup_iov.iov_base = setup_buf;
165 ret = writev(uredislog->fd, &setup_iov, 1);
166 if (ret <= 0) {
167 close(uredislog->fd);
168 uredislog->fd = -1;
169 return -1;
170 }
171 uwsgi_redis_logger_discard_response(uredislog);
172 }
173 if (uredislog->id) {
174 setup_iov.iov_len = snprintf(
175 setup_buf, sizeof (setup_buf), "*2\r\n$6\r\nselect\r\n$%zu\r\n%*s\r\n",
176 strlen(uredislog->id), (int)strlen(uredislog->id), uredislog->id);
177 setup_iov.iov_base = setup_buf;
178 ret = writev(uredislog->fd, &setup_iov, 1);
179 if (ret <= 0) {
180 close(uredislog->fd);
181 uredislog->fd = -1;
182 return -1;
183 }
184 uwsgi_redis_logger_discard_response(uredislog);
185 }
186 }
187
188 if (uredislog->fd == -1) return -1;
189
190 // drop newline
191 if (message[len-1] == '\n') len--;
192
193 uwsgi_num2str2(len + uredislog->iovec[4].iov_len, uredislog->msgsize);
194 uredislog->iovec[2].iov_len = strlen(uredislog->msgsize);
195
196 uredislog->iovec[5].iov_base = message;
197 uredislog->iovec[5].iov_len = len;
198
199 ret = writev(uredislog->fd, uredislog->iovec, 7);
200 if (ret <= 0) {
201 close(uredislog->fd);
202 uredislog->fd = -1;
203 return -1;
204 }
205
206 uwsgi_redis_logger_discard_response(uredislog);
207
208 return ret;
209
210 }
211
uwsgi_redislog_register()212 void uwsgi_redislog_register() {
213 uwsgi_register_logger("redislog", uwsgi_redis_logger);
214 }
215
216 struct uwsgi_plugin redislog_plugin = {
217
218 .name = "redislog",
219 .on_load = uwsgi_redislog_register,
220
221 };
222
223