passenger 4.0.42 → 4.0.43

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of passenger might be problematic. Click here for more details.

Files changed (67) hide show
  1. checksums.yaml +8 -8
  2. checksums.yaml.gz.asc +7 -7
  3. data.tar.gz.asc +7 -7
  4. data/CHANGELOG +13 -0
  5. data/CONTRIBUTING.md +2 -19
  6. data/build/agents.rb +4 -1
  7. data/build/cxx_tests.rb +7 -2
  8. data/build/debian.rb +1 -1
  9. data/debian.template/control.template +0 -2
  10. data/doc/CodingTipsAndPitfalls.md +56 -0
  11. data/doc/Users guide Apache.idmap.txt +16 -14
  12. data/doc/Users guide Nginx.idmap.txt +8 -6
  13. data/doc/Users guide Standalone.idmap.txt +3 -1
  14. data/doc/Users guide Standalone.txt +1 -1
  15. data/doc/users_guide_snippets/environment_variables.txt +1 -0
  16. data/doc/users_guide_snippets/installation.txt +5 -5
  17. data/doc/users_guide_snippets/support_information.txt +42 -9
  18. data/doc/users_guide_snippets/troubleshooting/default.txt +42 -0
  19. data/ext/common/ApplicationPool2/Common.h +1 -0
  20. data/ext/common/ApplicationPool2/DirectSpawner.h +2 -7
  21. data/ext/common/ApplicationPool2/DummySpawner.h +1 -1
  22. data/ext/common/ApplicationPool2/Group.h +4 -2
  23. data/ext/common/ApplicationPool2/Options.h +9 -7
  24. data/ext/common/ApplicationPool2/Pool.h +83 -40
  25. data/ext/common/ApplicationPool2/Process.h +2 -6
  26. data/ext/common/ApplicationPool2/README.md +0 -40
  27. data/ext/common/ApplicationPool2/SmartSpawner.h +2 -9
  28. data/ext/common/ApplicationPool2/Spawner.h +1 -4
  29. data/ext/common/ApplicationPool2/SpawnerFactory.h +6 -9
  30. data/ext/common/ApplicationPool2/SuperGroup.h +3 -3
  31. data/ext/common/Constants.h +1 -1
  32. data/ext/common/UnionStation/Connection.h +227 -0
  33. data/ext/common/UnionStation/Core.h +497 -0
  34. data/ext/common/UnionStation/ScopeLog.h +172 -0
  35. data/ext/common/UnionStation/Transaction.h +276 -0
  36. data/ext/common/Utils.cpp +83 -8
  37. data/ext/common/Utils.h +25 -4
  38. data/ext/common/Utils/AnsiColorConstants.h +1 -0
  39. data/ext/common/Utils/ProcessMetricsCollector.h +6 -170
  40. data/ext/common/Utils/SpeedMeter.h +258 -0
  41. data/ext/common/Utils/StrIntUtils.cpp +6 -0
  42. data/ext/common/Utils/StringScanning.h +277 -0
  43. data/ext/common/Utils/SystemMetricsCollector.h +1460 -0
  44. data/ext/common/agents/Base.cpp +8 -8
  45. data/ext/common/agents/HelperAgent/Main.cpp +12 -6
  46. data/ext/common/agents/HelperAgent/RequestHandler.h +15 -16
  47. data/ext/common/agents/HelperAgent/SystemMetricsTool.cpp +199 -0
  48. data/ext/common/agents/LoggingAgent/LoggingServer.h +2 -1
  49. data/ext/common/agents/SpawnPreparer.cpp +20 -32
  50. data/lib/phusion_passenger.rb +1 -1
  51. data/lib/phusion_passenger/config/list_instances_command.rb +118 -0
  52. data/lib/phusion_passenger/config/main.rb +22 -4
  53. data/lib/phusion_passenger/config/system_metrics_command.rb +37 -0
  54. data/lib/phusion_passenger/config/utils.rb +1 -1
  55. data/lib/phusion_passenger/loader_shared_helpers.rb +8 -5
  56. data/lib/phusion_passenger/platform_info/compiler.rb +1 -1
  57. data/resources/templates/error_layout.html.template +3 -3
  58. data/test/cxx/ApplicationPool2/DirectSpawnerTest.cpp +3 -5
  59. data/test/cxx/ApplicationPool2/PoolTest.cpp +1 -3
  60. data/test/cxx/ApplicationPool2/ProcessTest.cpp +4 -4
  61. data/test/cxx/ApplicationPool2/SmartSpawnerTest.cpp +5 -7
  62. data/test/cxx/RequestHandlerTest.cpp +9 -3
  63. data/test/cxx/UnionStationTest.cpp +61 -64
  64. metadata +13 -4
  65. metadata.gz.asc +7 -7
  66. data/ext/common/UnionStation.h +0 -968
  67. data/helper-scripts/system-memory-stats.py +0 -207
@@ -1,968 +0,0 @@
1
- /*
2
- * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2010-2013 Phusion
4
- *
5
- * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
- *
7
- * Permission is hereby granted, free of charge, to any person obtaining a copy
8
- * of this software and associated documentation files (the "Software"), to deal
9
- * in the Software without restriction, including without limitation the rights
10
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
- * copies of the Software, and to permit persons to whom the Software is
12
- * furnished to do so, subject to the following conditions:
13
- *
14
- * The above copyright notice and this permission notice shall be included in
15
- * all copies or substantial portions of the Software.
16
- *
17
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
- * THE SOFTWARE.
24
- */
25
- #ifndef _PASSENGER_UNION_STATION_H_
26
- #define _PASSENGER_UNION_STATION_H_
27
-
28
- #include <boost/shared_ptr.hpp>
29
- #include <boost/enable_shared_from_this.hpp>
30
- #include <boost/noncopyable.hpp>
31
- #include <oxt/thread.hpp>
32
- #include <oxt/system_calls.hpp>
33
- #include <oxt/backtrace.hpp>
34
-
35
- #include <sys/types.h>
36
- #include <sys/time.h>
37
- #include <sys/resource.h>
38
- #include <unistd.h>
39
- #include <fcntl.h>
40
- #include <pthread.h>
41
- #include <string>
42
- #include <map>
43
- #include <stdexcept>
44
- #include <cstdio>
45
- #include <ctime>
46
- #include <cerrno>
47
- #include <cassert>
48
-
49
- #include <RandomGenerator.h>
50
- #include <FileDescriptor.h>
51
- #include <StaticString.h>
52
- #include <Logging.h>
53
- #include <Exceptions.h>
54
- #include <Utils.h>
55
- #include <Utils/MessageIO.h>
56
- #include <Utils/StrIntUtils.h>
57
- #include <Utils/MD5.h>
58
- #include <Utils/SystemTime.h>
59
-
60
-
61
- namespace Passenger {
62
- namespace UnionStation {
63
-
64
- using namespace std;
65
- using namespace boost;
66
- using namespace oxt;
67
-
68
-
69
- // All access to the file descriptor must be synchronized through the lock.
70
- struct Connection {
71
- mutable boost::mutex syncher;
72
- int fd;
73
-
74
- Connection(int _fd)
75
- : fd(_fd)
76
- { }
77
-
78
- ~Connection() {
79
- disconnect();
80
- }
81
-
82
- bool connected() const {
83
- return fd != -1;
84
- }
85
-
86
- bool disconnect(string &errorResponse) {
87
- if (!connected()) {
88
- return false;
89
- }
90
-
91
- /* The server might send an "error" array message
92
- * just before disconnecting. Try to read it.
93
- */
94
- TRACE_POINT();
95
- vector<string> response;
96
- try {
97
- unsigned long long timeout = 20000000;
98
- while (true) {
99
- response = readArrayMessage(fd, &timeout);
100
- }
101
- } catch (const TimeoutException &) {
102
- /* This means that the last message isn't an array
103
- * message or that the server didn't send it quickly
104
- * enough. In any case, discard whatever previous
105
- * array messages we were able to read because they're
106
- * guaranteed not to be the error message we're expecting.
107
- */
108
- response.clear();
109
- } catch (const SystemException &e) {
110
- /* We treat ECONNRESET the same as EOFException.
111
- * Other errors are treated as TimeoutException.
112
- */
113
- if (e.code() != ECONNRESET) {
114
- response.clear();
115
- }
116
- } catch (const EOFException &) {
117
- /* Do nothing. We've successfully read the last array message. */
118
- }
119
-
120
- UPDATE_TRACE_POINT();
121
- disconnect();
122
-
123
- if (response.size() == 2 && response[0] == "error") {
124
- errorResponse = response[1];
125
- return true;
126
- } else {
127
- return false;
128
- }
129
- }
130
-
131
- void disconnect() {
132
- if (fd != -1) {
133
- this_thread::disable_interruption di;
134
- this_thread::disable_syscall_interruption dsi;
135
- safelyClose(fd);
136
- fd = -1;
137
- }
138
- }
139
- };
140
-
141
- typedef boost::shared_ptr<Connection> ConnectionPtr;
142
-
143
-
144
- /** A special lock type for Connection that also keeps a smart
145
- * pointer to the data structure so that the mutex is not destroyed
146
- * prematurely.
147
- */
148
- struct ConnectionLock {
149
- ConnectionPtr connection;
150
- bool locked;
151
-
152
- ConnectionLock(const ConnectionPtr &c)
153
- : connection(c)
154
- {
155
- c->syncher.lock();
156
- locked = true;
157
- }
158
-
159
- ~ConnectionLock() {
160
- if (locked) {
161
- connection->syncher.unlock();
162
- }
163
- }
164
-
165
- void reset(const ConnectionPtr &c, bool lockNow = true) {
166
- if (locked) {
167
- connection->syncher.unlock();
168
- }
169
- connection = c;
170
- if (lockNow) {
171
- connection->syncher.lock();
172
- locked = true;
173
- } else {
174
- locked = false;
175
- }
176
- }
177
-
178
- void lock() {
179
- assert(!locked);
180
- connection->syncher.lock();
181
- locked = true;
182
- }
183
- };
184
-
185
-
186
- /**
187
- * A scope guard which closes the given Connection on destruction unless cleared.
188
- */
189
- class ConnectionGuard {
190
- private:
191
- ConnectionPtr connection;
192
- bool cleared;
193
-
194
- public:
195
- ConnectionGuard(const ConnectionPtr &_connection)
196
- : connection(_connection),
197
- cleared(false)
198
- { }
199
-
200
- ~ConnectionGuard() {
201
- if (!cleared) {
202
- connection->disconnect();
203
- }
204
- }
205
-
206
- void clear() {
207
- cleared = true;
208
- }
209
- };
210
-
211
-
212
- enum ExceptionHandlingMode {
213
- PRINT,
214
- THROW,
215
- IGNORE
216
- };
217
-
218
-
219
- class LoggerFactory;
220
- typedef boost::shared_ptr<LoggerFactory> LoggerFactoryPtr;
221
-
222
- inline void _checkinConnection(const LoggerFactoryPtr &loggerFactory, const ConnectionPtr &connection);
223
-
224
-
225
- class Logger: public boost::noncopyable {
226
- private:
227
- static const int INT64_STR_BUFSIZE = 22; // Long enough for a 64-bit number.
228
- static const unsigned long long IO_TIMEOUT = 5000000; // In microseconds.
229
-
230
- const LoggerFactoryPtr loggerFactory;
231
- const ConnectionPtr connection;
232
- const string txnId;
233
- const string groupName;
234
- const string category;
235
- const string unionStationKey;
236
- const ExceptionHandlingMode exceptionHandlingMode;
237
- bool shouldFlushToDiskAfterClose;
238
-
239
- /**
240
- * Buffer must be at least txnId.size() + 1 + INT64_STR_BUFSIZE + 1 bytes.
241
- */
242
- char *insertTxnIdAndTimestamp(char *buffer, const char *end) {
243
- assert(end - buffer >= int(txnId.size() + 1 + INT64_STR_BUFSIZE + 1));
244
- int size;
245
-
246
- // "txn-id-here"
247
- buffer = appendData(buffer, end, txnId);
248
-
249
- // "txn-id-here "
250
- buffer = appendData(buffer, end, " ", 1);
251
-
252
- // "txn-id-here 123456"
253
- assert(end - buffer >= INT64_STR_BUFSIZE);
254
- size = snprintf(buffer, INT64_STR_BUFSIZE, "%llu", SystemTime::getUsec());
255
- if (size >= INT64_STR_BUFSIZE) {
256
- // The buffer is too small.
257
- throw IOException("Cannot format a new transaction log message timestamp.");
258
- }
259
- buffer += size;
260
-
261
- // "txn-id-here 123456 "
262
- buffer = appendData(buffer, end, " ", 1);
263
-
264
- return buffer;
265
- }
266
-
267
- template<typename ExceptionType>
268
- void handleException(const ExceptionType &e) {
269
- switch (exceptionHandlingMode) {
270
- case THROW:
271
- throw e;
272
- case PRINT: {
273
- const tracable_exception *te =
274
- dynamic_cast<const tracable_exception *>(&e);
275
- if (te != NULL) {
276
- P_WARN(te->what() << "\n" << te->backtrace());
277
- } else {
278
- P_WARN(e.what());
279
- }
280
- break;
281
- }
282
- default:
283
- break;
284
- }
285
- }
286
-
287
- public:
288
- Logger()
289
- : exceptionHandlingMode(PRINT)
290
- { }
291
-
292
- Logger(const LoggerFactoryPtr &_loggerFactory,
293
- const ConnectionPtr &_connection,
294
- const string &_txnId,
295
- const string &_groupName,
296
- const string &_category,
297
- const string &_unionStationKey,
298
- ExceptionHandlingMode _exceptionHandlingMode = PRINT)
299
- : loggerFactory(_loggerFactory),
300
- connection(_connection),
301
- txnId(_txnId),
302
- groupName(_groupName),
303
- category(_category),
304
- unionStationKey(_unionStationKey),
305
- exceptionHandlingMode(_exceptionHandlingMode),
306
- shouldFlushToDiskAfterClose(false)
307
- { }
308
-
309
- ~Logger() {
310
- TRACE_POINT();
311
- if (connection == NULL) {
312
- return;
313
- }
314
- ConnectionLock l(connection);
315
- if (!connection->connected()) {
316
- return;
317
- }
318
-
319
- char timestamp[2 * sizeof(unsigned long long) + 1];
320
- integerToHexatri<unsigned long long>(SystemTime::getUsec(),
321
- timestamp);
322
-
323
- UPDATE_TRACE_POINT();
324
- ConnectionGuard guard(connection);
325
- try {
326
- unsigned long long timeout = IO_TIMEOUT;
327
- writeArrayMessage(connection->fd, &timeout,
328
- "closeTransaction",
329
- txnId.c_str(),
330
- timestamp,
331
- NULL);
332
-
333
- if (shouldFlushToDiskAfterClose) {
334
- UPDATE_TRACE_POINT();
335
- timeout = IO_TIMEOUT;
336
- writeArrayMessage(connection->fd, &timeout,
337
- "flush", NULL);
338
- readArrayMessage(connection->fd, &timeout);
339
- }
340
-
341
- _checkinConnection(loggerFactory, connection);
342
- guard.clear();
343
- } catch (const SystemException &e) {
344
- string errorResponse;
345
-
346
- UPDATE_TRACE_POINT();
347
- guard.clear();
348
- if (connection->disconnect(errorResponse)) {
349
- handleException(IOException(
350
- "Logging agent disconnected with error: " +
351
- errorResponse));
352
- } else {
353
- handleException(e);
354
- }
355
- }
356
- }
357
-
358
- void message(const StaticString &text) {
359
- TRACE_POINT();
360
- if (connection == NULL) {
361
- P_TRACE(3, "[Union Station log to null] " << text);
362
- return;
363
- }
364
- ConnectionLock l(connection);
365
- if (!connection->connected()) {
366
- P_TRACE(3, "[Union Station log to null] " << text);
367
- return;
368
- }
369
-
370
- char timestamp[2 * sizeof(unsigned long long) + 1];
371
- integerToHexatri<unsigned long long>(SystemTime::getUsec(), timestamp);
372
-
373
- UPDATE_TRACE_POINT();
374
- ConnectionGuard guard(connection);
375
- try {
376
- unsigned long long timeout = IO_TIMEOUT;
377
- P_TRACE(3, "[Union Station log] " << txnId << " " << timestamp << " " << text);
378
- writeArrayMessage(connection->fd, &timeout,
379
- "log",
380
- txnId.c_str(),
381
- timestamp,
382
- NULL);
383
- writeScalarMessage(connection->fd, text, &timeout);
384
- guard.clear();
385
- } catch (const std::exception &e) {
386
- string errorResponse;
387
-
388
- UPDATE_TRACE_POINT();
389
- guard.clear();
390
- if (connection->disconnect(errorResponse)) {
391
- handleException(IOException(
392
- "Logging agent disconnected with error: " +
393
- errorResponse));
394
- } else {
395
- handleException(e);
396
- }
397
- }
398
- }
399
-
400
- void abort(const StaticString &text) {
401
- message("ABORT");
402
- }
403
-
404
- void flushToDiskAfterClose(bool value) {
405
- shouldFlushToDiskAfterClose = value;
406
- }
407
-
408
- bool isNull() const {
409
- return connection == NULL;
410
- }
411
-
412
- const string &getTxnId() const {
413
- return txnId;
414
- }
415
-
416
- const string &getGroupName() const {
417
- return groupName;
418
- }
419
-
420
- const string &getCategory() const {
421
- return category;
422
- }
423
-
424
- const string &getUnionStationKey() const {
425
- return unionStationKey;
426
- }
427
- };
428
-
429
- typedef boost::shared_ptr<Logger> LoggerPtr;
430
-
431
-
432
- class ScopeLog: public noncopyable {
433
- private:
434
- Logger * const log;
435
- enum {
436
- NAME,
437
- GRANULAR
438
- } type;
439
- union {
440
- const char *name;
441
- struct {
442
- const char *endMessage;
443
- const char *abortMessage;
444
- } granular;
445
- } data;
446
- bool ok;
447
-
448
- static string timevalToString(struct timeval &tv) {
449
- unsigned long long i = (unsigned long long) tv.tv_sec * 1000000 + tv.tv_usec;
450
- return usecToString(i);
451
- }
452
-
453
- static string usecToString(unsigned long long usec) {
454
- char timestamp[2 * sizeof(unsigned long long) + 1];
455
- integerToHexatri<unsigned long long>(usec, timestamp);
456
- return timestamp;
457
- }
458
-
459
- public:
460
- ScopeLog()
461
- : log(NULL)
462
- { }
463
-
464
- ScopeLog(const LoggerPtr &_log, const char *name)
465
- : log(_log.get())
466
- {
467
- type = NAME;
468
- data.name = name;
469
- ok = false;
470
-
471
- char message[150];
472
- char *pos = message;
473
- const char *end = message + sizeof(message);
474
- struct rusage usage;
475
-
476
- pos = appendData(pos, end, "BEGIN: ");
477
- pos = appendData(pos, end, name);
478
- pos = appendData(pos, end, " (");
479
- pos = appendData(pos, end, usecToString(SystemTime::getUsec()));
480
- pos = appendData(pos, end, ",");
481
- if (getrusage(RUSAGE_SELF, &usage) == -1) {
482
- int e = errno;
483
- throw SystemException("getrusage() failed", e);
484
- }
485
- pos = appendData(pos, end, timevalToString(usage.ru_utime));
486
- pos = appendData(pos, end, ",");
487
- pos = appendData(pos, end, timevalToString(usage.ru_stime));
488
- pos = appendData(pos, end, ") ");
489
-
490
- if (log != NULL) {
491
- log->message(StaticString(message, pos - message));
492
- }
493
- }
494
-
495
- ScopeLog(const LoggerPtr &_log,
496
- const char *beginMessage,
497
- const char *endMessage,
498
- const char *abortMessage = NULL)
499
- : log(_log.get())
500
- {
501
- if (_log != NULL) {
502
- type = GRANULAR;
503
- data.granular.endMessage = endMessage;
504
- data.granular.abortMessage = abortMessage;
505
- ok = abortMessage == NULL;
506
- _log->message(beginMessage);
507
- }
508
- }
509
-
510
- ~ScopeLog() {
511
- if (log == NULL) {
512
- return;
513
- }
514
- if (type == NAME) {
515
- char message[150];
516
- char *pos = message;
517
- const char *end = message + sizeof(message);
518
- struct rusage usage;
519
-
520
- if (ok) {
521
- pos = appendData(pos, end, "END: ");
522
- } else {
523
- pos = appendData(pos, end, "FAIL: ");
524
- }
525
- pos = appendData(pos, end, data.name);
526
- pos = appendData(pos, end, " (");
527
- pos = appendData(pos, end, usecToString(SystemTime::getUsec()));
528
- pos = appendData(pos, end, ",");
529
- if (getrusage(RUSAGE_SELF, &usage) == -1) {
530
- int e = errno;
531
- throw SystemException("getrusage() failed", e);
532
- }
533
- pos = appendData(pos, end, timevalToString(usage.ru_utime));
534
- pos = appendData(pos, end, ",");
535
- pos = appendData(pos, end, timevalToString(usage.ru_stime));
536
- pos = appendData(pos, end, ")");
537
-
538
- log->message(StaticString(message, pos - message));
539
- } else {
540
- if (ok) {
541
- log->message(data.granular.endMessage);
542
- } else {
543
- log->message(data.granular.abortMessage);
544
- }
545
- }
546
- }
547
-
548
- void success() {
549
- ok = true;
550
- }
551
- };
552
-
553
-
554
- class LoggerFactory: public boost::enable_shared_from_this<LoggerFactory> {
555
- private:
556
- static const unsigned int CONNECTION_POOL_MAX_SIZE = 10;
557
-
558
- const string serverAddress;
559
- const string username;
560
- const string password;
561
- const string nodeName;
562
- RandomGenerator randomGenerator;
563
-
564
- LoggerPtr nullLogger;
565
-
566
- /** Lock protecting the fields that follow, but not the
567
- * contents of the connection object.
568
- */
569
- mutable boost::mutex syncher;
570
- vector<ConnectionPtr> connectionPool;
571
- unsigned int maxConnectTries;
572
- unsigned long long reconnectTimeout;
573
- unsigned long long nextReconnectTime;
574
-
575
- static string determineNodeName(const string &givenNodeName) {
576
- if (givenNodeName.empty()) {
577
- return getHostName();
578
- } else {
579
- return givenNodeName;
580
- }
581
- }
582
-
583
- static bool isNetworkError(int code) {
584
- return code == EPIPE || code == ECONNREFUSED || code == ECONNRESET
585
- || code == EHOSTUNREACH || code == ENETDOWN || code == ENETUNREACH
586
- || code == ETIMEDOUT;
587
- }
588
-
589
- template<typename T>
590
- static bool instanceof(const std::exception &e) {
591
- return dynamic_cast<const T *>(&e) != NULL;
592
- }
593
-
594
- ConnectionPtr createNewConnection() {
595
- TRACE_POINT();
596
- int fd;
597
- vector<string> args;
598
- unsigned long long timeout = 15000000;
599
-
600
- fd = connectToServer(serverAddress);
601
- FdGuard guard(fd, true);
602
- if (!readArrayMessage(fd, args, &timeout)) {
603
- throw IOException("The logging agent closed the connection before sending a version identifier.");
604
- }
605
- if (args.size() != 2 || args[0] != "version") {
606
- throw IOException("The logging agent server didn't sent a valid version identifier.");
607
- }
608
- if (args[1] != "1") {
609
- string message = "Unsupported logging agent protocol version " +
610
- args[1] + ".";
611
- throw IOException(message);
612
- }
613
-
614
- UPDATE_TRACE_POINT();
615
- writeScalarMessage(fd, username, &timeout);
616
- writeScalarMessage(fd, password, &timeout);
617
-
618
- UPDATE_TRACE_POINT();
619
- if (!readArrayMessage(fd, args, &timeout)) {
620
- throw IOException("The logging agent did not send an authentication response.");
621
- } else if (args.size() != 1) {
622
- throw IOException("The authentication response that the logging agent sent is not valid.");
623
- } else if (args[0] != "ok") {
624
- throw SecurityException("The logging agent server denied authentication: " + args[0]);
625
- }
626
-
627
- UPDATE_TRACE_POINT();
628
- writeArrayMessage(fd, &timeout, "init", nodeName.c_str(), NULL);
629
- if (!readArrayMessage(fd, args, &timeout)) {
630
- throw SystemException("Cannot connect to logging server", ECONNREFUSED);
631
- } else if (args.size() != 1) {
632
- throw IOException("Logging server returned an invalid reply for the 'init' command");
633
- } else if (args[0] == "server shutting down") {
634
- throw SystemException("Cannot connect to server", ECONNREFUSED);
635
- } else if (args[0] != "ok") {
636
- throw IOException("Logging server returned an invalid reply for the 'init' command");
637
- }
638
-
639
- guard.clear();
640
- return boost::make_shared<Connection>(fd);
641
- }
642
-
643
- public:
644
- LoggerFactory() {
645
- nullLogger = boost::make_shared<Logger>();
646
- }
647
-
648
- LoggerFactory(const string &_serverAddress, const string &_username,
649
- const string &_password, const string &_nodeName = string())
650
- : serverAddress(_serverAddress),
651
- username(_username),
652
- password(_password),
653
- nodeName(determineNodeName(_nodeName))
654
- {
655
- nullLogger = boost::make_shared<Logger>();
656
- if (!_serverAddress.empty() && isLocalSocketAddress(_serverAddress)) {
657
- maxConnectTries = 10;
658
- } else {
659
- maxConnectTries = 1;
660
- }
661
- reconnectTimeout = 1000000;
662
- nextReconnectTime = 0;
663
- }
664
-
665
- ConnectionPtr checkoutConnection() {
666
- TRACE_POINT();
667
- boost::unique_lock<boost::mutex> l(syncher);
668
- if (!connectionPool.empty()) {
669
- P_TRACE(3, "Checked out existing connection");
670
- ConnectionPtr connection = connectionPool.back();
671
- connectionPool.pop_back();
672
- return connection;
673
-
674
- } else {
675
- if (SystemTime::getUsec() < nextReconnectTime) {
676
- P_TRACE(3, "Not yet time to reconnect; returning NULL connection");
677
- return ConnectionPtr();
678
- }
679
-
680
- l.unlock();
681
- P_TRACE(3, "Creating new connection with logging agent");
682
- ConnectionPtr connection;
683
- try {
684
- connection = createNewConnection();
685
- } catch (const TimeoutException &) {
686
- l.lock();
687
- P_WARN("Timeout trying to connect to the logging agent at " << serverAddress << "; " <<
688
- "will reconnect in " << reconnectTimeout / 1000000 << " second(s).");
689
- nextReconnectTime = SystemTime::getUsec() + reconnectTimeout;
690
- return ConnectionPtr();
691
- } catch (const tracable_exception &e) {
692
- l.lock();
693
- nextReconnectTime = SystemTime::getUsec() + reconnectTimeout;
694
- if (instanceof<IOException>(e) || instanceof<SystemException>(e)) {
695
- P_WARN("Cannot connect to the logging agent at " << serverAddress <<
696
- " (" << e.what() << "); will reconnect in " <<
697
- reconnectTimeout / 1000000 << " second(s).");
698
- return ConnectionPtr();
699
- } else {
700
- throw;
701
- }
702
- }
703
-
704
- return connection;
705
- }
706
- }
707
-
708
- void checkinConnection(const ConnectionPtr &connection) {
709
- boost::lock_guard<boost::mutex> l(syncher);
710
- if (connectionPool.size() < CONNECTION_POOL_MAX_SIZE) {
711
- connectionPool.push_back(connection);
712
- } else {
713
- connection->disconnect();
714
- }
715
- }
716
-
717
- LoggerPtr createNullLogger() const {
718
- return nullLogger;
719
- }
720
-
721
- LoggerPtr newTransaction(const string &groupName,
722
- const string &category = "requests",
723
- const string &unionStationKey = "-",
724
- const string &filters = string())
725
- {
726
- if (serverAddress.empty()) {
727
- return createNullLogger();
728
- }
729
-
730
- unsigned long long timestamp = SystemTime::getUsec();
731
- char txnId[
732
- 2 * sizeof(unsigned int) + // max hex timestamp size
733
- 11 + // space for a random identifier
734
- 1 // null terminator
735
- ];
736
- char *end;
737
- unsigned int timestampSize;
738
- char timestampStr[2 * sizeof(unsigned long long) + 1];
739
-
740
- // "[timestamp]"
741
- // Our timestamp is like a Unix timestamp but with minutes
742
- // resolution instead of seconds. 32 bits will last us for
743
- // about 8000 years.
744
- timestampSize = integerToHexatri<unsigned int>(timestamp / 1000000 / 60,
745
- txnId);
746
- end = txnId + timestampSize;
747
-
748
- // "[timestamp]-"
749
- *end = '-';
750
- end++;
751
-
752
- // "[timestamp]-[random id]"
753
- randomGenerator.generateAsciiString(end, 11);
754
- end += 11;
755
- *end = '\0';
756
-
757
- integerToHexatri<unsigned long long>(timestamp, timestampStr);
758
-
759
- ConnectionPtr connection = checkoutConnection();
760
- if (connection == NULL) {
761
- return createNullLogger();
762
- }
763
-
764
- ConnectionLock cl(connection);
765
- ConnectionGuard guard(connection);
766
-
767
- try {
768
- unsigned long long timeout = 15000000;
769
-
770
- writeArrayMessage(connection->fd, &timeout,
771
- "openTransaction",
772
- txnId,
773
- groupName.c_str(),
774
- "",
775
- category.c_str(),
776
- timestampStr,
777
- unionStationKey.c_str(),
778
- "true",
779
- "true",
780
- filters.c_str(),
781
- NULL);
782
-
783
- vector<string> args;
784
- if (!readArrayMessage(connection->fd, args, &timeout)) {
785
- boost::lock_guard<boost::mutex> l(syncher);
786
- P_WARN("The logging agent at " << serverAddress <<
787
- " closed the connection (no error message given);" <<
788
- " will reconnect in " << reconnectTimeout / 1000000 <<
789
- " second(s).");
790
- nextReconnectTime = SystemTime::getUsec() + reconnectTimeout;
791
- return createNullLogger();
792
- } else if (args.size() == 2 && args[0] == "error") {
793
- boost::lock_guard<boost::mutex> l(syncher);
794
- P_WARN("The logging agent at " << serverAddress <<
795
- " closed the connection (error message: " << args[1] <<
796
- "); will reconnect in " << reconnectTimeout / 1000000 <<
797
- " second(s).");
798
- nextReconnectTime = SystemTime::getUsec() + reconnectTimeout;
799
- return createNullLogger();
800
- } else if (args.empty() || args[0] != "ok") {
801
- boost::lock_guard<boost::mutex> l(syncher);
802
- P_WARN("The logging agent at " << serverAddress <<
803
- " sent an unexpected reply;" <<
804
- " will reconnect in " << reconnectTimeout / 1000000 <<
805
- " second(s).");
806
- nextReconnectTime = SystemTime::getUsec() + reconnectTimeout;
807
- return createNullLogger();
808
- }
809
-
810
- guard.clear();
811
- return boost::make_shared<Logger>(shared_from_this(),
812
- connection,
813
- string(txnId, end - txnId),
814
- groupName, category,
815
- unionStationKey);
816
-
817
- } catch (const TimeoutException &) {
818
- boost::lock_guard<boost::mutex> l(syncher);
819
- P_WARN("Timeout trying to communicate with the logging agent at " << serverAddress << "; " <<
820
- "will reconnect in " << reconnectTimeout / 1000000 << " second(s).");
821
- nextReconnectTime = SystemTime::getUsec() + reconnectTimeout;
822
- return createNullLogger();
823
-
824
- } catch (const SystemException &e) {
825
- if (e.code() == ENOENT || isNetworkError(e.code())) {
826
- string errorResponse;
827
- bool gotErrorResponse;
828
-
829
- guard.clear();
830
- gotErrorResponse = connection->disconnect(errorResponse);
831
- boost::lock_guard<boost::mutex> l(syncher);
832
- if (gotErrorResponse) {
833
- P_WARN("The logging agent at " << serverAddress <<
834
- " closed the connection (error message: " << errorResponse <<
835
- "); will reconnect in " << reconnectTimeout / 1000000 <<
836
- " second(s).");
837
- } else {
838
- P_WARN("The logging agent at " << serverAddress <<
839
- " closed the connection (no error message given);" <<
840
- " will reconnect in " << reconnectTimeout / 1000000 <<
841
- " second(s).");
842
- }
843
- nextReconnectTime = SystemTime::getUsec() + reconnectTimeout;
844
- return createNullLogger();
845
- } else {
846
- throw;
847
- }
848
- }
849
- }
850
-
851
- LoggerPtr continueTransaction(const string &txnId,
852
- const string &groupName,
853
- const string &category = "requests",
854
- const string &unionStationKey = "-")
855
- {
856
- if (serverAddress.empty() || txnId.empty()) {
857
- return createNullLogger();
858
- }
859
-
860
- char timestampStr[2 * sizeof(unsigned long long) + 1];
861
- integerToHexatri<unsigned long long>(SystemTime::getUsec(), timestampStr);
862
-
863
- ConnectionPtr connection = checkoutConnection();
864
- if (connection == NULL) {
865
- return createNullLogger();
866
- }
867
-
868
- ConnectionLock cl(connection);
869
- ConnectionGuard guard(connection);
870
-
871
- try {
872
- unsigned long long timeout = 15000000;
873
- writeArrayMessage(connection->fd, &timeout,
874
- "openTransaction",
875
- txnId.c_str(),
876
- groupName.c_str(),
877
- "",
878
- category.c_str(),
879
- timestampStr,
880
- unionStationKey.c_str(),
881
- "true",
882
- NULL);
883
- guard.clear();
884
- return boost::make_shared<Logger>(shared_from_this(),
885
- connection,
886
- txnId, groupName, category,
887
- unionStationKey);
888
-
889
- } catch (const TimeoutException &) {
890
- boost::lock_guard<boost::mutex> l(syncher);
891
- P_WARN("Timeout trying to communicate with the logging agent at " << serverAddress << "; " <<
892
- "will reconnect in " << reconnectTimeout / 1000000 << " second(s).");
893
- nextReconnectTime = SystemTime::getUsec() + reconnectTimeout;
894
- return createNullLogger();
895
-
896
- } catch (const SystemException &e) {
897
- if (e.code() == ENOENT || isNetworkError(e.code())) {
898
- string errorResponse;
899
- bool gotErrorResponse;
900
-
901
- guard.clear();
902
- gotErrorResponse = connection->disconnect(errorResponse);
903
- boost::lock_guard<boost::mutex> l(syncher);
904
- if (gotErrorResponse) {
905
- P_WARN("The logging agent at " << serverAddress <<
906
- " closed the connection (error message: " << errorResponse <<
907
- "); will reconnect in " << reconnectTimeout / 1000000 <<
908
- " second(s).");
909
- } else {
910
- P_WARN("The logging agent at " << serverAddress <<
911
- " closed the connection (no error message given);" <<
912
- " will reconnect in " << reconnectTimeout / 1000000 <<
913
- " second(s).");
914
- }
915
- nextReconnectTime = SystemTime::getUsec() + reconnectTimeout;
916
- return createNullLogger();
917
- } else {
918
- throw;
919
- }
920
- }
921
- }
922
-
923
- void setMaxConnectTries(unsigned int value) {
924
- boost::lock_guard<boost::mutex> l(syncher);
925
- maxConnectTries = value;
926
- }
927
-
928
- void setReconnectTimeout(unsigned long long usec) {
929
- boost::lock_guard<boost::mutex> l(syncher);
930
- reconnectTimeout = usec;
931
- }
932
-
933
- bool isNull() const {
934
- return serverAddress.empty();
935
- }
936
-
937
- const string &getAddress() const {
938
- return serverAddress;
939
- }
940
-
941
- const string &getUsername() const {
942
- return username;
943
- }
944
-
945
- const string &getPassword() const {
946
- return password;
947
- }
948
-
949
- /**
950
- * @post !result.empty()
951
- */
952
- const string &getNodeName() const {
953
- return nodeName;
954
- }
955
- };
956
-
957
-
958
- inline void
959
- _checkinConnection(const LoggerFactoryPtr &loggerFactory, const ConnectionPtr &connection) {
960
- loggerFactory->checkinConnection(connection);
961
- }
962
-
963
-
964
- } // namespace UnionStation
965
- } // namespace Passenger
966
-
967
- #endif /* _PASSENGER_UNION_STATION_H_ */
968
-