passenger 4.0.45 → 4.0.46

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 (94) hide show
  1. checksums.yaml +8 -8
  2. checksums.yaml.gz.asc +7 -7
  3. data.tar.gz.asc +7 -7
  4. data/.editorconfig +19 -0
  5. data/CHANGELOG +47 -0
  6. data/CONTRIBUTING.md +9 -1
  7. data/CONTRIBUTORS +4 -0
  8. data/Vagrantfile +7 -3
  9. data/build/agents.rb +1 -0
  10. data/build/misc.rb +6 -4
  11. data/dev/vagrant/bashrc +2 -0
  12. data/doc/Design and Architecture.txt +9 -7
  13. data/doc/Users guide Apache.idmap.txt +2 -0
  14. data/doc/Users guide Apache.txt +24 -4
  15. data/doc/Users guide Nginx.idmap.txt +4 -0
  16. data/doc/Users guide Nginx.txt +23 -4
  17. data/doc/images/code_walkthrough.jpg +0 -0
  18. data/doc/users_guide_snippets/installation.txt +38 -0
  19. data/ext/common/AgentsStarter.h +6 -1
  20. data/ext/common/ApplicationPool2/Common.h +17 -2
  21. data/ext/common/ApplicationPool2/DirectSpawner.h +5 -11
  22. data/ext/common/ApplicationPool2/DummySpawner.h +2 -4
  23. data/ext/common/ApplicationPool2/ErrorRenderer.h +119 -0
  24. data/ext/common/ApplicationPool2/Implementation.cpp +159 -11
  25. data/ext/common/ApplicationPool2/Options.h +16 -7
  26. data/ext/common/ApplicationPool2/Pool.h +28 -24
  27. data/ext/common/ApplicationPool2/Process.h +1 -9
  28. data/ext/common/ApplicationPool2/SmartSpawner.h +15 -18
  29. data/ext/common/ApplicationPool2/Spawner.h +18 -14
  30. data/ext/common/ApplicationPool2/SpawnerFactory.h +12 -30
  31. data/ext/common/Constants.h +1 -1
  32. data/ext/common/Exceptions.h +15 -2
  33. data/ext/common/UnionStation/Core.h +9 -0
  34. data/ext/common/Utils/JsonUtils.h +53 -0
  35. data/ext/common/Utils/ProcessMetricsCollector.h +1 -1
  36. data/ext/common/Utils/SpeedMeter.h +7 -3
  37. data/ext/common/Utils/SystemMetricsCollector.h +8 -6
  38. data/ext/common/agents/HelperAgent/Main.cpp +4 -4
  39. data/ext/common/agents/HelperAgent/RequestHandler.h +115 -56
  40. data/ext/nginx/ConfigurationCommands.c +1 -1
  41. data/ext/nginx/ConfigurationCommands.c.erb +6 -1
  42. data/ext/nginx/ContentHandler.c +2 -1
  43. data/ext/nginx/config +1 -1
  44. data/helper-scripts/node-loader.js +23 -0
  45. data/helper-scripts/wsgi-loader.py +12 -4
  46. data/lib/phusion_passenger.rb +1 -1
  47. data/lib/phusion_passenger/active_support3_extensions/init.rb +39 -78
  48. data/lib/phusion_passenger/constants.rb +3 -1
  49. data/lib/phusion_passenger/loader_shared_helpers.rb +10 -5
  50. data/lib/phusion_passenger/nginx/config_options.rb +3 -1
  51. data/lib/phusion_passenger/packaging.rb +1 -0
  52. data/lib/phusion_passenger/public_api.rb +108 -16
  53. data/lib/phusion_passenger/rack/thread_handler_extension.rb +1 -0
  54. data/lib/phusion_passenger/request_handler.rb +2 -2
  55. data/lib/phusion_passenger/request_handler/thread_handler.rb +28 -46
  56. data/lib/phusion_passenger/standalone/command.rb +8 -1
  57. data/lib/phusion_passenger/standalone/main.rb +0 -1
  58. data/lib/phusion_passenger/standalone/start_command.rb +4 -0
  59. data/lib/phusion_passenger/union_station/connection.rb +67 -0
  60. data/lib/phusion_passenger/{analytics_logger.rb → union_station/core.rb} +55 -256
  61. data/lib/phusion_passenger/union_station/transaction.rb +168 -0
  62. data/lib/phusion_passenger/utils.rb +4 -0
  63. data/lib/phusion_passenger/utils/lock.rb +62 -0
  64. data/resources/mime.types +1 -0
  65. data/resources/templates/error_layout.html.template +2 -0
  66. data/resources/templates/standalone/config.erb +1 -0
  67. data/test/cxx/ApplicationPool2/DirectSpawnerTest.cpp +5 -3
  68. data/test/cxx/ApplicationPool2/PoolTest.cpp +13 -3
  69. data/test/cxx/ApplicationPool2/SmartSpawnerTest.cpp +16 -13
  70. data/test/cxx/ApplicationPool2/SpawnerTestCases.cpp +6 -0
  71. data/test/cxx/FileBackedPipeTest.cpp +1 -1
  72. data/test/cxx/RequestHandlerTest.cpp +158 -2
  73. data/test/cxx/ServerInstanceDirTest.cpp +2 -0
  74. data/test/cxx/TestSupport.h +21 -2
  75. data/test/cxx/UtilsTest.cpp +1 -0
  76. data/test/ruby/classic_rails/loader_spec.rb +0 -1
  77. data/test/ruby/classic_rails/preloader_spec.rb +0 -1
  78. data/test/ruby/rails3.0/loader_spec.rb +2 -2
  79. data/test/ruby/rails3.0/preloader_spec.rb +2 -2
  80. data/test/ruby/rails3.1/loader_spec.rb +2 -2
  81. data/test/ruby/rails3.1/preloader_spec.rb +2 -2
  82. data/test/ruby/rails3.2/loader_spec.rb +2 -2
  83. data/test/ruby/rails3.2/preloader_spec.rb +2 -2
  84. data/test/ruby/rails4.0/loader_spec.rb +2 -2
  85. data/test/ruby/rails4.0/preloader_spec.rb +2 -2
  86. data/test/ruby/request_handler_spec.rb +8 -8
  87. data/test/ruby/shared/rails/{analytics_logging_extensions_sharedspec.rb → union_station_extensions_sharedspec.rb} +5 -4
  88. data/test/ruby/union_station_spec.rb +283 -0
  89. data/test/stub/wsgi/passenger_wsgi.py +41 -5
  90. metadata +12 -7
  91. metadata.gz.asc +7 -7
  92. data/helper-scripts/wsgi-preloader.py +0 -1
  93. data/lib/phusion_passenger/standalone/package_runtime_command.rb +0 -105
  94. data/test/ruby/analytics_logger_spec.rb +0 -283
@@ -141,6 +141,9 @@ sudo apt-get install nginx-extras passenger
141
141
  --------------------------------------------------------------
142
142
  +
143
143
  3. Edit `/etc/nginx/nginx.conf` and uncomment `passenger_root` and `passenger_ruby`.
144
+ +
145
+ Especially <<PassengerRoot,passenger_root>> is important: Phusion Passenger won't work without it! If you don't see a commented version of `passenger_root` inside nginx.conf, then you need to <<inserting_passenger_root_for_apt,insert it yourself>>.
146
+ +
144
147
  4. Restart Nginx:
145
148
  +
146
149
  --------------------------------------------------------------
@@ -180,6 +183,9 @@ ifdef::nginx[]
180
183
  sudo apt-get install nginx-extras passenger-enterprise
181
184
  --------------------------------------------------------------
182
185
  4. Edit `/etc/nginx/nginx.conf` and uncomment `passenger_root` and `passenger_ruby`.
186
+ +
187
+ Especially <<PassengerRoot,passenger_root>> is important: Phusion Passenger won't work without it! If you don't see a commented version of `passenger_root` inside nginx.conf, then you need to <<inserting_passenger_root_for_apt,insert it yourself>>.
188
+ +
183
189
  5. Restart Nginx:
184
190
  +
185
191
  --------------------------------------------------------------
@@ -204,6 +210,38 @@ sudo apt-get install passenger-enterprise
204
210
  --------------------------------------------------------------
205
211
  endif::[]
206
212
 
213
+ ifdef::nginx[]
214
+ [[inserting_passenger_root_for_apt]]
215
+ ==== Inserting `passenger_root` into nginx.conf
216
+
217
+ During step 3 of the 'Installing packages' subsection, you were instructed to uncomment the <<PassengerRoot,passenger_root>> directive in `/etc/nginx/nginx.conf`. If there is no commented version in there, then you need to insert it yourself.
218
+
219
+ First, run the following command and take note of its output:
220
+
221
+ -----------------------------------
222
+ /usr/bin/passenger-config --root
223
+ -----------------------------------
224
+
225
+ Next, insert the following snippet into `/etc/nginx/nginx.conf`, under the `http` block:
226
+
227
+ -------------------------------------------------------------
228
+ passenger_root whatever_value_you_got_from_previous_command;
229
+ -------------------------------------------------------------
230
+
231
+ Here is an example:
232
+
233
+ -------------------------------------------------------------
234
+ ...
235
+ http {
236
+ # path-to-locations.ini is given to you by `passenger-config --root`.
237
+ passenger_root /path-to-locations.ini;
238
+ ...
239
+ }
240
+ -------------------------------------------------------------
241
+
242
+ Once you're done editing nginx.conf, continue with step 4.
243
+ endif::nginx[]
244
+
207
245
 
208
246
  === Installing or upgrading on Red Hat, Fedora, CentOS or ScientificLinux
209
247
 
@@ -535,10 +535,13 @@ public:
535
535
  guard.clear();
536
536
  if (e == ENOENT) {
537
537
  string passengerRootConfig;
538
+ string docURL;
538
539
  if (type == AS_APACHE) {
539
540
  passengerRootConfig = "PassengerRoot";
541
+ docURL = APACHE2_DOC_URL "#PassengerRoot";
540
542
  } else {
541
543
  passengerRootConfig = "passenger_root";
544
+ docURL = NGINX_DOC_URL "#PassengerRoot";
542
545
  }
543
546
  throw RuntimeException("Unable to start the Phusion Passenger watchdog "
544
547
  "because its executable (" + watchdogFilename + ") does "
@@ -546,7 +549,9 @@ public:
546
549
  "installation is broken or incomplete, or that your '" +
547
550
  passengerRootConfig + "' directive is set to the wrong value. "
548
551
  "Please reinstall Phusion Passenger or fix your '" +
549
- passengerRootConfig + "' directive, whichever is applicable.");
552
+ passengerRootConfig + "' directive, whichever is applicable. "
553
+ "To learn how to fix '" + passengerRootConfig + "', please read " +
554
+ docURL);
550
555
  } else {
551
556
  throw SystemException("Unable to start the Phusion Passenger watchdog (" +
552
557
  watchdogFilename + ")", e);
@@ -29,7 +29,10 @@
29
29
  #include <boost/shared_ptr.hpp>
30
30
  #include <boost/function.hpp>
31
31
  #include <oxt/tracable_exception.hpp>
32
+ #include <ResourceLocator.h>
32
33
  #include <RandomGenerator.h>
34
+ #include <UnionStation/Core.h>
35
+ #include <UnionStation/Transaction.h>
33
36
  #include <ApplicationPool2/Options.h>
34
37
  #include <Utils/StringMap.h>
35
38
 
@@ -183,6 +186,12 @@ struct Ticket {
183
186
  };
184
187
 
185
188
  struct SpawnerConfig {
189
+ // Used by error pages.
190
+ ResourceLocator resourceLocator;
191
+
192
+ // Used for Union Station logging.
193
+ UnionStation::CorePtr unionStationCore;
194
+
186
195
  // Used by SmartSpawner and DirectSpawner.
187
196
  /** A random generator to use. */
188
197
  RandomGeneratorPtr randomGenerator;
@@ -192,8 +201,12 @@ struct SpawnerConfig {
192
201
  unsigned int spawnerCreationSleepTime;
193
202
  unsigned int spawnTime;
194
203
 
195
- SpawnerConfig(const RandomGeneratorPtr &randomGenerator = RandomGeneratorPtr())
196
- : concurrency(1),
204
+ SpawnerConfig(const ResourceLocator &_resourceLocator,
205
+ const UnionStation::CorePtr &_unionStationCore = UnionStation::CorePtr(),
206
+ const RandomGeneratorPtr &randomGenerator = RandomGeneratorPtr())
207
+ : resourceLocator(_resourceLocator),
208
+ unionStationCore(_unionStationCore),
209
+ concurrency(1),
197
210
  spawnerCreationSleepTime(0),
198
211
  spawnTime(0)
199
212
  {
@@ -209,6 +222,8 @@ typedef boost::shared_ptr<SpawnerConfig> SpawnerConfigPtr;
209
222
 
210
223
  ExceptionPtr copyException(const tracable_exception &e);
211
224
  void rethrowException(const ExceptionPtr &e);
225
+ void processAndLogNewSpawnException(SpawnException &e, const Options &options,
226
+ const SpawnerConfigPtr &config);
212
227
 
213
228
  } // namespace ApplicationPool2
214
229
  } // namespace Passenger
@@ -111,10 +111,10 @@ private:
111
111
  shared_array<const char *> &args) const
112
112
  {
113
113
  vector<string> startCommandArgs;
114
- string agentsDir = resourceLocator.getAgentsDir();
114
+ string agentsDir = config->resourceLocator.getAgentsDir();
115
115
  vector<string> command;
116
116
 
117
- split(options.getStartCommand(resourceLocator), '\t', startCommandArgs);
117
+ split(options.getStartCommand(config->resourceLocator), '\t', startCommandArgs);
118
118
  if (startCommandArgs.empty()) {
119
119
  throw RuntimeException("No startCommand given");
120
120
  }
@@ -144,17 +144,11 @@ private:
144
144
  }
145
145
 
146
146
  public:
147
- DirectSpawner(const ResourceLocator &_resourceLocator,
148
- const ServerInstanceDir::GenerationPtr &_generation,
149
- const SpawnerConfigPtr &_config = SpawnerConfigPtr())
150
- : Spawner(_resourceLocator)
147
+ DirectSpawner(const ServerInstanceDir::GenerationPtr &_generation,
148
+ const SpawnerConfigPtr &_config)
149
+ : Spawner(_config)
151
150
  {
152
151
  generation = _generation;
153
- if (_config == NULL) {
154
- config = boost::make_shared<SpawnerConfig>();
155
- } else {
156
- config = _config;
157
- }
158
152
  }
159
153
 
160
154
  virtual ProcessPtr spawn(const Options &options) {
@@ -37,16 +37,14 @@ using namespace oxt;
37
37
 
38
38
  class DummySpawner: public Spawner {
39
39
  private:
40
- SpawnerConfigPtr config;
41
40
  boost::mutex lock;
42
41
  unsigned int count;
43
42
 
44
43
  public:
45
44
  unsigned int cleanCount;
46
45
 
47
- DummySpawner(const ResourceLocator &resourceLocator, const SpawnerConfigPtr &_config)
48
- : Spawner(resourceLocator),
49
- config(_config)
46
+ DummySpawner(const SpawnerConfigPtr &_config)
47
+ : Spawner(_config)
50
48
  {
51
49
  count = 0;
52
50
  cleanCount = 0;
@@ -0,0 +1,119 @@
1
+ /*
2
+ * Phusion Passenger - https://www.phusionpassenger.com/
3
+ * Copyright (c) 2014 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_APPLICATION_POOL2_ERROR_RENDERER_H_
26
+ #define _PASSENGER_APPLICATION_POOL2_ERROR_RENDERER_H_
27
+
28
+ #include <string>
29
+ #include <map>
30
+ #include <cctype>
31
+
32
+ #include <ApplicationPool2/Options.h>
33
+ #include <Constants.h>
34
+ #include <ResourceLocator.h>
35
+ #include <StaticString.h>
36
+ #include <Exceptions.h>
37
+ #include <Utils/StringMap.h>
38
+ #include <Utils/Template.h>
39
+ #include <Utils/IOUtils.h>
40
+
41
+ namespace Passenger {
42
+ namespace ApplicationPool2 {
43
+
44
+ using namespace std;
45
+ using namespace boost;
46
+ using namespace oxt;
47
+
48
+
49
+ class ErrorRenderer {
50
+ private:
51
+ string templatesDir, cssFile, errorLayoutFile;
52
+
53
+ public:
54
+ ErrorRenderer(const ResourceLocator &resourceLocator) {
55
+ templatesDir = resourceLocator.getResourcesDir() + "/templates";
56
+ cssFile = templatesDir + "/error_layout.css";
57
+ errorLayoutFile = templatesDir + "/error_layout.html.template";
58
+ }
59
+
60
+ string renderWithDetails(const StaticString &message,
61
+ const Options &options,
62
+ const SpawnException *e = NULL) const
63
+ {
64
+ string generalErrorFile =
65
+ (e != NULL && e->isHTML())
66
+ ? templatesDir + "/general_error_with_html.html.template"
67
+ : templatesDir + "/general_error.html.template";
68
+ string css = readAll(cssFile);
69
+ StringMap<StaticString> params;
70
+
71
+ params.set("CSS", css);
72
+ params.set("APP_ROOT", options.appRoot);
73
+ params.set("RUBY", options.ruby);
74
+ params.set("ENVIRONMENT", options.environment);
75
+ params.set("MESSAGE", message);
76
+ params.set("IS_RUBY_APP",
77
+ (options.appType == "classic-rails" || options.appType == "rack")
78
+ ? "true" : "false");
79
+ if (e != NULL) {
80
+ params.set("TITLE", "Web application could not be started");
81
+ // Store all SpawnException annotations into 'params',
82
+ // but convert its name to uppercase.
83
+ const map<string, string> &annotations = e->getAnnotations();
84
+ map<string, string>::const_iterator it, end = annotations.end();
85
+ for (it = annotations.begin(); it != end; it++) {
86
+ string name = it->first;
87
+ for (string::size_type i = 0; i < name.size(); i++) {
88
+ name[i] = toupper(name[i]);
89
+ }
90
+ params.set(name, it->second);
91
+ }
92
+ } else {
93
+ params.set("TITLE", "Internal server error");
94
+ }
95
+
96
+ string content = Template::apply(readAll(generalErrorFile), params);
97
+ params.set("CONTENT", content);
98
+
99
+ return Template::apply(readAll(errorLayoutFile), params);
100
+ }
101
+
102
+ string renderWithoutDetails() const {
103
+ string templateFile = templatesDir + "/undisclosed_error.html.template";
104
+ StringMap<StaticString> params;
105
+
106
+ params.set("PROGRAM_NAME", PROGRAM_NAME);
107
+ params.set("NGINX_DOC_URL", NGINX_DOC_URL);
108
+ params.set("APACHE2_DOC_URL", APACHE2_DOC_URL);
109
+ params.set("STANDALONE_DOC_URL", STANDALONE_DOC_URL);
110
+
111
+ return Template::apply(readAll(templateFile), params);
112
+ }
113
+ };
114
+
115
+
116
+ } // namespace ApplicationPool2
117
+ } // namespace Passenger
118
+
119
+ #endif /* _PASSENGER_APPLICATION_POOL2_ERROR_RENDERER_H_ */
@@ -25,6 +25,8 @@
25
25
  #include <typeinfo>
26
26
  #include <algorithm>
27
27
  #include <utility>
28
+ #include <sstream>
29
+ #include <limits.h>
28
30
  #include <boost/make_shared.hpp>
29
31
  #include <boost/date_time/posix_time/posix_time_types.hpp>
30
32
  #include <oxt/backtrace.hpp>
@@ -32,10 +34,13 @@
32
34
  #include <ApplicationPool2/SuperGroup.h>
33
35
  #include <ApplicationPool2/Group.h>
34
36
  #include <ApplicationPool2/PipeWatcher.h>
37
+ #include <ApplicationPool2/ErrorRenderer.h>
35
38
  #include <Exceptions.h>
36
39
  #include <MessageReadersWriters.h>
40
+ #include <Utils.h>
37
41
  #include <Utils/ScopeGuard.h>
38
42
  #include <Utils/MessageIO.h>
43
+ #include <Utils/JsonUtils.h>
39
44
 
40
45
  namespace Passenger {
41
46
  namespace ApplicationPool2 {
@@ -136,6 +141,146 @@ rethrowException(const ExceptionPtr &e) {
136
141
  throw tracable_exception(*e);
137
142
  }
138
143
 
144
+ void processAndLogNewSpawnException(SpawnException &e, const Options &options,
145
+ const SpawnerConfigPtr &config)
146
+ {
147
+ TRACE_POINT();
148
+ UnionStation::TransactionPtr transaction;
149
+ ErrorRenderer renderer(config->resourceLocator);
150
+ string appMessage = e.getErrorPage();
151
+ string errorId;
152
+ char filename[PATH_MAX];
153
+ stringstream stream;
154
+
155
+ if (options.analytics && config->unionStationCore != NULL) {
156
+ try {
157
+ UPDATE_TRACE_POINT();
158
+ transaction = config->unionStationCore->newTransaction(
159
+ options.getAppGroupName(),
160
+ "exceptions",
161
+ options.unionStationKey);
162
+ errorId = transaction->getTxnId();
163
+ } catch (const tracable_exception &e2) {
164
+ transaction.reset();
165
+ P_WARN("Cannot log to Union Station: " << e2.what() <<
166
+ "\n Backtrace:\n" << e2.backtrace());
167
+ }
168
+ }
169
+
170
+ UPDATE_TRACE_POINT();
171
+ if (appMessage.empty()) {
172
+ appMessage = "none";
173
+ }
174
+ if (errorId.empty()) {
175
+ errorId = config->randomGenerator->generateHexString(4);
176
+ }
177
+ e.set("error_id", errorId);
178
+
179
+ try {
180
+ int fd = -1;
181
+ FdGuard guard(fd, true);
182
+ string errorPage;
183
+
184
+ UPDATE_TRACE_POINT();
185
+ errorPage = renderer.renderWithDetails(appMessage, options, &e);
186
+
187
+ #if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
188
+ snprintf(filename, PATH_MAX, "%s/passenger-error-XXXXXX.html",
189
+ getSystemTempDir());
190
+ fd = mkstemps(filename, sizeof(".html") - 1);
191
+ #else
192
+ snprintf(filename, PATH_MAX, "%s/passenger-error.XXXXXX",
193
+ getSystemTempDir());
194
+ fd = mkstemp(filename);
195
+ #endif
196
+ if (fd == -1) {
197
+ int e = errno;
198
+ throw SystemException("Cannot generate a temporary filename",
199
+ e);
200
+ }
201
+
202
+ UPDATE_TRACE_POINT();
203
+ writeExact(fd, errorPage);
204
+ } catch (const SystemException &e2) {
205
+ filename[0] = '\0';
206
+ P_ERROR("Cannot render an error page: " << e2.what() << "\n" <<
207
+ e2.backtrace());
208
+ }
209
+
210
+ if (transaction != NULL) {
211
+ try {
212
+ UPDATE_TRACE_POINT();
213
+ transaction->message("Context: spawning");
214
+ transaction->message("Message: " +
215
+ jsonString(e.what()));
216
+ transaction->message("App message: " +
217
+ jsonString(appMessage));
218
+
219
+ const char *kind;
220
+ switch (e.getErrorKind()) {
221
+ case SpawnException::PRELOADER_STARTUP_ERROR:
222
+ kind = "PRELOADER_STARTUP_ERROR";
223
+ break;
224
+ case SpawnException::PRELOADER_STARTUP_PROTOCOL_ERROR:
225
+ kind = "PRELOADER_STARTUP_PROTOCOL_ERROR";
226
+ break;
227
+ case SpawnException::PRELOADER_STARTUP_TIMEOUT:
228
+ kind = "PRELOADER_STARTUP_TIMEOUT";
229
+ break;
230
+ case SpawnException::PRELOADER_STARTUP_EXPLAINABLE_ERROR:
231
+ kind = "PRELOADER_STARTUP_EXPLAINABLE_ERROR";
232
+ break;
233
+ case SpawnException::APP_STARTUP_ERROR:
234
+ kind = "APP_STARTUP_ERROR";
235
+ break;
236
+ case SpawnException::APP_STARTUP_PROTOCOL_ERROR:
237
+ kind = "APP_STARTUP_PROTOCOL_ERROR";
238
+ break;
239
+ case SpawnException::APP_STARTUP_TIMEOUT:
240
+ kind = "APP_STARTUP_TIMEOUT";
241
+ break;
242
+ case SpawnException::APP_STARTUP_EXPLAINABLE_ERROR:
243
+ kind = "APP_STARTUP_EXPLAINABLE_ERROR";
244
+ break;
245
+ default:
246
+ kind = "UNDEFINED_ERROR";
247
+ break;
248
+ }
249
+ transaction->message(string("Kind: ") + kind);
250
+
251
+ Json::Value details;
252
+ const map<string, string> &annotations = e.getAnnotations();
253
+ map<string, string>::const_iterator it, end = annotations.end();
254
+
255
+ for (it = annotations.begin(); it != end; it++) {
256
+ details[it->first] = it->second;
257
+ }
258
+
259
+ // This information is not very useful. Union Station
260
+ // already collects system metrics.
261
+ details.removeMember("system_metrics");
262
+ // Don't include environment variables because they may
263
+ // contain sensitive information.
264
+ details.removeMember("envvars");
265
+
266
+ transaction->message("Details: " + stringifyJson(details));
267
+ } catch (const tracable_exception &e2) {
268
+ P_WARN("Cannot log to Union Station: " << e2.what() <<
269
+ "\n Backtrace:\n" << e2.backtrace());
270
+ }
271
+ }
272
+
273
+ UPDATE_TRACE_POINT();
274
+ stream << "Could not spawn process for application " << options.appRoot <<
275
+ ": " << e.what() << "\n" <<
276
+ " Error ID: " << errorId << "\n";
277
+ if (filename[0] != '\0') {
278
+ stream << " Error details saved to: " << filename << "\n";
279
+ }
280
+ stream << " Message from application: " << appMessage << "\n";
281
+ P_ERROR(stream.str());
282
+ }
283
+
139
284
 
140
285
  const SuperGroupPtr
141
286
  Pool::getSuperGroup(const char *name) {
@@ -155,7 +300,7 @@ SuperGroup::runAllActions(const vector<Callback> &actions) {
155
300
 
156
301
  string
157
302
  SuperGroup::generateSecret() const {
158
- return getPool()->randomGenerator->generateAsciiString(43);
303
+ return getPool()->getRandomGenerator()->generateAsciiString(43);
159
304
  }
160
305
 
161
306
  void
@@ -187,6 +332,8 @@ SuperGroup::realDoInitialize(const Options &options, unsigned int generation) {
187
332
  vector<ComponentInfo> componentInfos;
188
333
  vector<ComponentInfo>::const_iterator it;
189
334
  ExceptionPtr exception;
335
+
336
+ PoolPtr pool = getPool();
190
337
 
191
338
  P_TRACE(2, "Initializing SuperGroup " << inspect() << " in the background...");
192
339
  try {
@@ -198,13 +345,15 @@ SuperGroup::realDoInitialize(const Options &options, unsigned int generation) {
198
345
  string message = "The directory " +
199
346
  options.appRoot +
200
347
  " does not seem to contain a web application.";
201
- exception = boost::make_shared<SpawnException>(
202
- message, message, false);
348
+ boost::shared_ptr<SpawnException> spawnException =
349
+ boost::make_shared<SpawnException>(
350
+ message, message, false);
351
+ exception = spawnException;
352
+ processAndLogNewSpawnException(*spawnException, options,
353
+ pool->getSpawnerConfig());
203
354
  }
204
355
 
205
- PoolPtr pool = getPool();
206
356
  Pool::DebugSupportPtr debug = pool->debugSupport;
207
-
208
357
  vector<Callback> actions;
209
358
  {
210
359
  if (debug != NULL && debug->superGroup) {
@@ -805,7 +954,9 @@ Group::spawnThreadRealMain(const SpawnerPtr &spawner, const Options &options, un
805
954
  this_thread::restore_interruption ri(di);
806
955
  this_thread::restore_syscall_interruption rsi(dsi);
807
956
  if (shouldFail) {
808
- throw SpawnException("Simulated failure");
957
+ SpawnException e("Simulated failure");
958
+ processAndLogNewSpawnException(e, options, pool->getSpawnerConfig());
959
+ throw e;
809
960
  } else {
810
961
  process = spawner->spawn(options);
811
962
  process->setGroup(shared_from_this());
@@ -878,9 +1029,6 @@ Group::spawnThreadRealMain(const SpawnerPtr &spawner, const Options &options, un
878
1029
  } else {
879
1030
  // TODO: sure this is the best thing? if there are
880
1031
  // processes currently alive we should just use them.
881
- P_ERROR("Could not spawn process for group " << name <<
882
- ": " << exception->what() << "\n" <<
883
- exception->backtrace());
884
1032
  if (enabledCount == 0) {
885
1033
  enableAllDisablingProcesses(actions);
886
1034
  }
@@ -1197,7 +1345,7 @@ Group::testOverflowRequestQueue() const {
1197
1345
 
1198
1346
  const ResourceLocator &
1199
1347
  Group::getResourceLocator() const {
1200
- return getPool()->spawnerFactory->getResourceLocator();
1348
+ return getPool()->getSpawnerConfig()->resourceLocator;
1201
1349
  }
1202
1350
 
1203
1351
  // 'process' is not a reference so that bind(runAttachHooks, ...) causes the shared
@@ -1222,7 +1370,7 @@ Group::setupAttachOrDetachHook(const ProcessPtr process, HookScriptOptions &opti
1222
1370
 
1223
1371
  string
1224
1372
  Group::generateSecret(const SuperGroupPtr &superGroup) {
1225
- return superGroup->getPool()->randomGenerator->generateAsciiString(43);
1373
+ return superGroup->getPool()->getRandomGenerator()->generateAsciiString(43);
1226
1374
  }
1227
1375
 
1228
1376