trinidad 1.4.0.RC → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
- }