trinidad 1.4.0.RC → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,5 +1,8 @@
1
- == Trinidad 1.4.0.RC (2012-07-03)
1
+ == Trinidad 1.4.0 (2012-07-24)
2
2
 
3
+ * fix incorrect context-param parsing and only configure logging when
4
+ deployment descriptor did not specified jruby.rack.logging param (#76)
5
+ * deep symbolize_options should account for arrays of hashes (#80)
3
6
  * requires latest Tomcat 7.0.28 (jars 1.0.5) due context reloading fix
4
7
  * requires latest jruby-rack 1.1.7 due delegating RackLogger to JUL
5
8
  * Trinidad::WebApp API revisited some changes are non-backwards compatible !
data/README.md CHANGED
@@ -145,15 +145,23 @@ Context with name [/] has completed rolling
145
145
  ```
146
146
 
147
147
  It also prints warnings and error messages on error output, while application
148
- specific log messages (e.g. logs from `Rails.logger`) go into the expected file
149
- location at *log/{environment}.log*.
148
+ specific log messages (e.g. logs from `Rails.logger`) always go into the expected
149
+ file location at *log/{environment}.log*.
150
150
 
151
- Application logging performs daily rolling out of the box and only prints
152
- messages from an application to the console while it runs in development mode.
151
+ Application logging performs daily file rolling out of the box and only prints
152
+ messages to the console while it runs in development mode, that means you won't
153
+ see any application specific output on the console say in production !
153
154
 
154
155
  Please note that these logging details as well as the logging format will be
155
156
  configurable with *trinidad.yml/.rb* within the next **1.4.x** release.
156
157
 
158
+ If you plan to use a slice of Java with your JRuby and require a logger, consider
159
+ using `ServletContext#log`. By default it is setup in a way that logging with
160
+ `ServletContext` ends up in the same location as the Rails log.
161
+ If this is not enough you can still configure a Java logging library e.g. SLF4J,
162
+ just make sure you tell Trinidad to use it as well, if needed, using the
163
+ **jruby.rack.logging** context parameter in *web.xml*.
164
+
157
165
  ## Hot Deployment
158
166
 
159
167
  Trinidad supports monitoring a file to reload applications, when the file
@@ -170,10 +178,10 @@ Since version **1.4.0** Trinidad supports 2 reload strategies :
170
178
 
171
179
  * **rolling** "zero-downtime" (asynchronous) reloading strategy similar to
172
180
  Passenger's rolling reloads. This has been the default since **1.1.0** up till
173
- Trinidad version **1.3.0**. If you use this you should account that while
174
- rolling memory requirements for the JVM might increase quite a lot since
175
- requests are being served and there's 2 versions of your application loaded at
176
- the same time.
181
+ the **1.3.x** line. If you use this you should account that your JVM memory
182
+ requirements might increase quite a lot (esp. if you reload under heavy loads)
183
+ since requests are being served while there's another version of the
184
+ application being loaded.
177
185
 
178
186
  Configure the reload strategy per web application or globally e.g. :
179
187
 
@@ -90,8 +90,13 @@ module Trinidad
90
90
  # a Hash like #symbolize helper
91
91
  def self.symbolize_options(options, deep = true)
92
92
  new_options = options.class.new
93
- options.each do |key, value|
94
- if deep && options_like?(value)
93
+ options.each do |key, value|
94
+ if deep && value.is_a?(Array) # YAML::Omap is an Array
95
+ array = new_options[key.to_sym] = value.class.new
96
+ value.each do |v|
97
+ array << ( options_like?(v) ? symbolize_options(v, deep) : v )
98
+ end
99
+ elsif deep && options_like?(value)
95
100
  new_options[key.to_sym] = symbolize_options(value, deep)
96
101
  else
97
102
  new_options[key.to_sym] = value
@@ -52,14 +52,14 @@ module Trinidad
52
52
  def self.configure_web_app(web_app, context)
53
53
  param_name, param_value = 'jruby.rack.logging', 'JUL'
54
54
  # 1. delegate (jruby-rack) servlet log to JUL
55
- if set_value = context.find_parameter(param_name)
55
+ if set_value = web_app_context_param(web_app, context, param_name)
56
56
  return nil if set_value.upcase != param_value
57
57
  else
58
58
  context.add_parameter(param_name, param_value)
59
59
  end
60
60
  # 2. use Tomcat's JUL logger name (unless set) :
61
61
  param_name = 'jruby.rack.logging.name'
62
- unless logger_name = context.find_parameter(param_name)
62
+ unless logger_name = web_app_context_param(web_app, context, param_name)
63
63
  # for a context path e.g. '/foo' most likely smt of the following :
64
64
  # org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/foo]
65
65
  context.add_parameter(param_name, logger_name = context.send(:logName))
@@ -118,6 +118,10 @@ module Trinidad
118
118
  logger.level = JUL::Level::WARNING if logger
119
119
  end
120
120
 
121
+ def self.web_app_context_param(web_app, context, name)
122
+ context.find_parameter(name) || web_app.web_xml_context_param(name)
123
+ end
124
+
121
125
  # we'd achieve logging to a production.log file while rotating it (daily)
122
126
  class FileHandler < Java::OrgApacheJuli::FileHandler # :nodoc
123
127
 
@@ -1,3 +1,3 @@
1
1
  module Trinidad
2
- VERSION = '1.4.0.RC'
2
+ VERSION = '1.4.0'
3
3
  end
@@ -147,29 +147,31 @@ module Trinidad
147
147
  config[:web_app_dir] ||= default_config[:web_app_dir] || Dir.pwd
148
148
  end
149
149
 
150
+ public
151
+
150
152
  def web_xml_servlet?(servlet_class, servlet_name = nil)
151
153
  !!( web_xml_doc && (
152
- web_xml_doc.root.elements["/web-app/servlet[contains(servlet-class, '#{servlet_class}')]"]
154
+ web_xml_doc.root.elements["/web-app/servlet[servlet-class = '#{servlet_class}']"]
153
155
  )
154
156
  )
155
157
  end
156
158
 
157
159
  def web_xml_filter?(filter_class)
158
160
  !!( web_xml_doc && (
159
- web_xml_doc.root.elements["/web-app/filter[contains(filter-class, '#{filter_class}')]"]
161
+ web_xml_doc.root.elements["/web-app/filter[filter-class = '#{filter_class}']"]
160
162
  )
161
163
  )
162
164
  end
163
165
 
164
166
  def web_xml_listener?(listener_class)
165
167
  !!( web_xml_doc &&
166
- web_xml_doc.root.elements["/web-app/listener[contains(listener-class, '#{listener_class}')]"]
168
+ web_xml_doc.root.elements["/web-app/listener[listener-class = '#{listener_class}']"]
167
169
  )
168
170
  end
169
171
 
170
172
  def web_xml_context_param(name)
171
173
  if web_xml_doc &&
172
- param = web_xml_doc.root.elements["/web-app/context-param[contains(param-name, '#{name}')]"]
174
+ param = web_xml_doc.root.elements["/web-app/context-param[param-name = '#{name}']"]
173
175
  param.elements['param-value'].text
174
176
  end
175
177
  end
data/trinidad.gemspec CHANGED
@@ -34,6 +34,7 @@ Gem::Specification.new do |s|
34
34
  s.files = `git ls-files`.split("\n").sort.
35
35
  reject { |file| file =~ /^\./ }. # .gitignore, .travis.yml
36
36
  reject { |file| file =~ /^spec\// }. # spec/**/*.spec
37
+ reject { |file| file =~ /^src\// }. # src/* patched into tomcat-core.jar
37
38
  # reject trinidad_jars.gemspec files :
38
39
  reject { |file| file == 'trinidad_jars.gemspec' ||
39
40
  file == 'lib/trinidad/jars.rb' ||
metadata CHANGED
@@ -1,8 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trinidad
3
3
  version: !ruby/object:Gem::Version
4
- prerelease: 6
5
- version: 1.4.0.RC
4
+ prerelease:
5
+ version: 1.4.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - David Calavera
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2012-07-03 00:00:00 Z
13
+ date: 2012-07-24 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: trinidad_jars
@@ -135,7 +135,6 @@ files:
135
135
  - rakelib/tomcat.rake
136
136
  - rakelib/trinidad.rake
137
137
  - rakelib/trinidad_jars.rake
138
- - src/java/org/apache/juli/FileHandler.java
139
138
  - trinidad.gemspec
140
139
  homepage: http://github.com/trinidad/trinidad
141
140
  licenses: []
@@ -154,9 +153,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
154
153
  required_rubygems_version: !ruby/object:Gem::Requirement
155
154
  none: false
156
155
  requirements:
157
- - - ">"
156
+ - - ">="
158
157
  - !ruby/object:Gem::Version
159
- version: 1.3.1
158
+ version: "0"
160
159
  requirements: []
161
160
 
162
161
  rubyforge_project: trinidad
@@ -1,401 +0,0 @@
1
- /*
2
- * Licensed to the Apache Software Foundation (ASF) under one or more
3
- * contributor license agreements. See the NOTICE file distributed with
4
- * this work for additional information regarding copyright ownership.
5
- * The ASF licenses this file to You under the Apache License, Version 2.0
6
- * (the "License"); you may not use this file except in compliance with
7
- * the License. You may obtain a copy of the License at
8
- *
9
- * http://www.apache.org/licenses/LICENSE-2.0
10
- *
11
- * Unless required by applicable law or agreed to in writing, software
12
- * distributed under the License is distributed on an "AS IS" BASIS,
13
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- * See the License for the specific language governing permissions and
15
- * limitations under the License.
16
- */
17
-
18
-
19
- package org.apache.juli;
20
-
21
- import java.io.BufferedOutputStream;
22
- import java.io.File;
23
- import java.io.FileOutputStream;
24
- import java.io.OutputStream;
25
- import java.io.OutputStreamWriter;
26
- import java.io.PrintWriter;
27
- import java.io.UnsupportedEncodingException;
28
- import java.sql.Timestamp;
29
- import java.util.concurrent.locks.ReadWriteLock;
30
- import java.util.concurrent.locks.ReentrantReadWriteLock;
31
- import java.util.logging.ErrorManager;
32
- import java.util.logging.Filter;
33
- import java.util.logging.Formatter;
34
- import java.util.logging.Handler;
35
- import java.util.logging.Level;
36
- import java.util.logging.LogManager;
37
- import java.util.logging.LogRecord;
38
- import java.util.logging.SimpleFormatter;
39
-
40
- /**
41
- * Implementation of <b>Handler</b> that appends log messages to a file
42
- * named {prefix}{date}{suffix} in a configured directory.
43
- *
44
- * <p>The following configuration properties are available:</p>
45
- *
46
- * <ul>
47
- * <li><code>directory</code> - The directory where to create the log file.
48
- * If the path is not absolute, it is relative to the current working
49
- * directory of the application. The Apache Tomcat configuration files usually
50
- * specify an absolute path for this property,
51
- * <code>${catalina.base}/logs</code>
52
- * Default value: <code>logs</code></li>
53
- * <li><code>rotatable</code> - If <code>true</code>, the log file will be
54
- * rotated on the first write past midnight and the filename will be
55
- * <code>{prefix}{date}{suffix}</code>, where date is yyyy-MM-dd. If <code>false</code>,
56
- * the file will not be rotated and the filename will be <code>{prefix}{suffix}</code>.
57
- * Default value: <code>true</code></li>
58
- * <li><code>prefix</code> - The leading part of the log file name.
59
- * Default value: <code>juli.</code></li>
60
- * <li><code>suffix</code> - The trailing part of the log file name. Default value: <code>.log</code></li>
61
- * <li><code>bufferSize</code> - Configures buffering. The value of <code>0</code>
62
- * uses system default buffering (typically an 8K buffer will be used). A
63
- * value of <code>&lt;0</code> forces a writer flush upon each log write. A
64
- * value <code>&gt;0</code> uses a BufferedOutputStream with the defined
65
- * value but note that the system default buffering will also be
66
- * applied. Default value: <code>-1</code></li>
67
- * <li><code>encoding</code> - Character set used by the log file. Default value:
68
- * empty string, which means to use the system default character set.</li>
69
- * <li><code>level</code> - The level threshold for this Handler. See the
70
- * <code>java.util.logging.Level</code> class for the possible levels.
71
- * Default value: <code>ALL</code></li>
72
- * <li><code>filter</code> - The <code>java.util.logging.Filter</code>
73
- * implementation class name for this Handler. Default value: unset</li>
74
- * <li><code>formatter</code> - The <code>java.util.logging.Formatter</code>
75
- * implementation class name for this Handler. Default value:
76
- * <code>java.util.logging.SimpleFormatter</code></li>
77
- * </ul>
78
- *
79
- * @version $Id$
80
- */
81
-
82
- public class FileHandler
83
- extends Handler {
84
-
85
-
86
- // ------------------------------------------------------------ Constructor
87
-
88
-
89
- public FileHandler() {
90
- this(null, null, null);
91
- }
92
-
93
-
94
- public FileHandler(String directory, String prefix, String suffix) {
95
- this.directory = directory;
96
- this.prefix = prefix;
97
- this.suffix = suffix;
98
- configure();
99
- }
100
-
101
- public FileHandler(String directory, String prefix, String suffix, boolean rotatable, int bufferSize) {
102
- this.directory = directory;
103
- this.prefix = prefix;
104
- this.suffix = suffix;
105
- this.rotatable = rotatable;
106
- this.bufferSize = bufferSize;
107
- configure();
108
- }
109
-
110
- // ----------------------------------------------------- Instance Variables
111
-
112
-
113
- /**
114
- * The directory in which log files are created.
115
- */
116
- private String directory;
117
-
118
- /**
119
- * The prefix that is added to log file filenames.
120
- */
121
- private String prefix;
122
-
123
- /**
124
- * The suffix that is added to log file filenames.
125
- */
126
- private String suffix;
127
-
128
- /**
129
- * Determines whether the logfile is rotatable
130
- */
131
- private Boolean rotatable;
132
-
133
- /**
134
- * Log buffer size.
135
- */
136
- private Integer bufferSize;
137
-
138
- /**
139
- * The as-of date for the currently open log file, or null if there is no
140
- * open log file.
141
- */
142
- private volatile String date = null;
143
-
144
- /**
145
- * The PrintWriter to which we are currently logging, if any.
146
- */
147
- private volatile PrintWriter writer = null;
148
-
149
- /**
150
- * Lock used to control access to the writer.
151
- */
152
- protected final ReadWriteLock writerLock = new ReentrantReadWriteLock();
153
-
154
- // --------------------------------------------------------- Public Methods
155
-
156
-
157
- /**
158
- * Format and publish a <tt>LogRecord</tt>.
159
- *
160
- * @param record description of the log event
161
- */
162
- @Override
163
- public void publish(LogRecord record) {
164
-
165
- if (!isLoggable(record)) {
166
- return;
167
- }
168
-
169
- final String tsDate = rotatable ?
170
- new Timestamp(System.currentTimeMillis()).toString().substring(0, 10) : "";
171
-
172
- try {
173
- writerLock.readLock().lock();
174
- // If the date has changed, switch log files
175
- // Construct the timestamp we will use, if requested
176
- // (... if not rotatable this will happen only once)
177
- if ( !tsDate.equals(date) ) {
178
- try {
179
- // Update to writeLock before we switch
180
- writerLock.readLock().unlock();
181
- writerLock.writeLock().lock();
182
-
183
- // Make sure another thread hasn't already done this
184
- if ( !tsDate.equals(date) ) {
185
- closeWriter();
186
- date = tsDate;
187
- openWriter();
188
- }
189
- } finally {
190
- writerLock.writeLock().unlock();
191
- // Down grade to read-lock. This ensures the writer remains valid
192
- // until the log message is written
193
- writerLock.readLock().lock();
194
- }
195
- }
196
-
197
- String result = null;
198
- try {
199
- result = getFormatter().format(record);
200
- } catch (Exception e) {
201
- reportError(null, e, ErrorManager.FORMAT_FAILURE);
202
- return;
203
- }
204
-
205
- try {
206
- if (writer!=null) {
207
- writer.write(result);
208
- if (bufferSize == null || bufferSize < 0) {
209
- writer.flush();
210
- }
211
- } else {
212
- reportError("FileHandler is closed or not yet initialized, unable to log ["+result+"]", null, ErrorManager.WRITE_FAILURE);
213
- }
214
- } catch (Exception e) {
215
- reportError(null, e, ErrorManager.WRITE_FAILURE);
216
- return;
217
- }
218
- } finally {
219
- writerLock.readLock().unlock();
220
- }
221
- }
222
-
223
-
224
- // -------------------------------------------------------- Private Methods
225
-
226
-
227
- /**
228
- * Close the currently open log file (if any).
229
- */
230
- @Override
231
- public void close() {
232
- closeWriter();
233
- }
234
-
235
- protected void closeWriter() {
236
-
237
- writerLock.writeLock().lock();
238
- try {
239
- if (writer == null)
240
- return;
241
- writer.write(getFormatter().getTail(this));
242
- writer.flush();
243
- writer.close();
244
- writer = null;
245
- date = null;
246
- } catch (Exception e) {
247
- reportError(null, e, ErrorManager.CLOSE_FAILURE);
248
- } finally {
249
- writerLock.writeLock().unlock();
250
- }
251
- }
252
-
253
-
254
- /**
255
- * Flush the writer.
256
- */
257
- @Override
258
- public void flush() {
259
-
260
- writerLock.readLock().lock();
261
- try {
262
- if (writer == null)
263
- return;
264
- writer.flush();
265
- } catch (Exception e) {
266
- reportError(null, e, ErrorManager.FLUSH_FAILURE);
267
- } finally {
268
- writerLock.readLock().unlock();
269
- }
270
-
271
- }
272
-
273
- /**
274
- * Configure from <code>LogManager</code> properties.
275
- */
276
- private void configure() {
277
-
278
- Timestamp ts = new Timestamp(System.currentTimeMillis());
279
- date = ts.toString().substring(0, 10);
280
-
281
- String className = this.getClass().getName(); //allow classes to override
282
-
283
- ClassLoader cl = Thread.currentThread().getContextClassLoader();
284
-
285
- // Retrieve configuration of logging file name
286
- if (rotatable == null)
287
- rotatable = Boolean.parseBoolean(getProperty(className + ".rotatable", "true"));
288
- if (directory == null)
289
- directory = getProperty(className + ".directory", "logs");
290
- if (prefix == null)
291
- prefix = getProperty(className + ".prefix", "juli.");
292
- if (suffix == null)
293
- suffix = getProperty(className + ".suffix", ".log");
294
- if (bufferSize == null) {
295
- String sBufferSize = getProperty(className + ".bufferSize", null);
296
- try {
297
- bufferSize = sBufferSize != null ? Integer.parseInt(sBufferSize) : null;
298
- } catch (NumberFormatException ignore) { /* no op */ }
299
- }
300
- // Get encoding for the logging file
301
- String encoding = getProperty(className + ".encoding", null);
302
- if (encoding != null && encoding.length() > 0) {
303
- try {
304
- setEncoding(encoding);
305
- } catch (UnsupportedEncodingException ex) {
306
- // Ignore
307
- }
308
- }
309
-
310
- // Get logging level for the handler
311
- setLevel(Level.parse(getProperty(className + ".level", "" + Level.ALL)));
312
-
313
- // Get filter configuration
314
- String filterName = getProperty(className + ".filter", null);
315
- if (filterName != null) {
316
- try {
317
- setFilter((Filter) cl.loadClass(filterName).newInstance());
318
- } catch (Exception e) {
319
- // Ignore
320
- }
321
- }
322
-
323
- // Set formatter
324
- String formatterName = getProperty(className + ".formatter", null);
325
- if (formatterName != null) {
326
- try {
327
- setFormatter((Formatter) cl.loadClass(formatterName).newInstance());
328
- } catch (Exception e) {
329
- // Ignore and fallback to defaults
330
- setFormatter(new SimpleFormatter());
331
- }
332
- } else {
333
- setFormatter(new SimpleFormatter());
334
- }
335
-
336
- // Set error manager
337
- setErrorManager(new ErrorManager());
338
-
339
- }
340
-
341
-
342
- private String getProperty(String name, String defaultValue) {
343
- String value = LogManager.getLogManager().getProperty(name);
344
- if (value == null) {
345
- value = defaultValue;
346
- } else {
347
- value = value.trim();
348
- }
349
- return value;
350
- }
351
-
352
-
353
- /**
354
- * Open the new log file for the date specified by <code>date</code>.
355
- */
356
- public void open() {
357
- openWriter();
358
- }
359
-
360
- protected void openWriter() {
361
-
362
- // Create the directory if necessary
363
- final File dir = new File(directory);
364
- if ( !checkDir(dir) ) {
365
- writer = null; return;
366
- }
367
-
368
- // Open the current log file
369
- writerLock.writeLock().lock();
370
- String logFileName = prefix + (rotatable ? date : "") + suffix;
371
- try {
372
- File logFile = new File(dir.getAbsoluteFile(), logFileName);
373
- if ( !checkDir(logFile.getParentFile()) ) {
374
- writer = null; return;
375
- }
376
- String encoding = getEncoding();
377
- FileOutputStream fos = new FileOutputStream(logFile, true);
378
- OutputStream os = (bufferSize != null && bufferSize > 0) ?
379
- new BufferedOutputStream(fos, bufferSize) : fos;
380
- writer = new PrintWriter(
381
- (encoding != null) ? new OutputStreamWriter(os, encoding)
382
- : new OutputStreamWriter(os), false);
383
- writer.write(getFormatter().getHead(this));
384
- } catch (Exception e) {
385
- reportError(null, e, ErrorManager.OPEN_FAILURE);
386
- writer = null;
387
- } finally {
388
- writerLock.writeLock().unlock();
389
- }
390
-
391
- }
392
-
393
- private boolean checkDir(final File dir) {
394
- if ( !dir.mkdirs() && !dir.isDirectory() ) {
395
- reportError("Unable to create [" + dir + "]", null, ErrorManager.OPEN_FAILURE);
396
- return false;
397
- }
398
- return true;
399
- }
400
-
401
- }