Initial revision
[OpenSRF.git] / src / javascript / opensrf_config.js
1 /** @file oils_config.js
2   * Config code and Logger code
3   * The config module is simple.  It parses an xml config file and 
4   * the values from the file are accessed via XPATH queries.
5   */
6
7 /** Searches up from Mozilla's chrome directory for the client 
8   * config file and returns the file object
9   */
10 function get_config_file() {
11
12         var dirService = Components.classes["@mozilla.org/file/directory_service;1"].
13                 getService( Components.interfaces.nsIProperties );
14
15         chromeDir = dirService.get( "AChrom",  Components.interfaces.nsIFile );
16         chromeDir.append("evergreen");
17         chromeDir.append("content");
18         chromeDir.append("conf");
19         chromeDir.append("client_config.xml");
20         return chromeDir;
21
22 }
23
24
25 /** Constructor. You may provide an optional path to the config file. **/
26 function Config( config_file ) {
27
28         if( Config.config != null ) { return Config.config; }
29
30         config_file = get_config_file();
31
32         // ------------------------------------------------------------------
33         // Grab the data from the config file
34         // ------------------------------------------------------------------
35         var data = "";
36         var fstream = Components.classes["@mozilla.org/network/file-input-stream;1"]
37                         .createInstance(Components.interfaces.nsIFileInputStream);
38
39         var sstream = Components.classes["@mozilla.org/scriptableinputstream;1"]
40                         .createInstance(Components.interfaces.nsIScriptableInputStream);
41
42         fstream.init(config_file, 1, 0, false);
43         sstream.init(fstream);
44         data += sstream.read(-1);
45
46         sstream.close();
47         fstream.close();
48         
49         
50
51         var DOMParser = new Components.Constructor(
52                 "@mozilla.org/xmlextras/domparser;1", "nsIDOMParser" );
53
54         this.config_doc = new DOMParser().parseFromString( data, "text/xml" );
55
56         Config.config = this;
57
58 }
59
60 /** Returns the value stored in the config file found with the
61   * given xpath expression
62   * E.g.  config.get_value( "/oils_config/dirs/log_dir" );
63   * Note, the 'oils_config' node is the base of the xpath expression,
64   * so something like this will also work:
65   * config.get_value( "dirs/log_dir" );
66   */
67 Config.prototype.get_value = function( xpath_query ) {
68
69         var evaluator = Components.classes["@mozilla.org/dom/xpath-evaluator;1"].
70                 createInstance( Components.interfaces.nsIDOMXPathEvaluator );
71
72         var xpath_obj = evaluator.evaluate( xpath_query, this.config_doc.documentElement, null, 0, null );
73         if( ! xpath_obj ) { return null; }
74
75         var node = xpath_obj.iterateNext();
76         if( node == null ) {
77                 throw new oils_ex_config( "No config option matching " + xpath_query );
78         }
79
80         return node.firstChild.nodeValue;
81 }       
82
83
84
85
86
87
88 // ------------------------------------------------------------------
89 // Logger code.
90 // ------------------------------------------------------------------
91 /** The global logging object */
92 Logger.logger           = null;
93 /** No logging level */
94 Logger.NONE                     = 0;
95 /** Error log level */
96 Logger.ERROR            = 1;
97 /** Info log level */
98 Logger.INFO                     = 2;
99 /* Debug log level */
100 Logger.DEBUG            = 3;
101
102 /** There exists a single logger object that all components share.
103   * Calling var logger = new Logger() will return the same one
104   * with each call.  This is so we only need one file handle for
105   * each type of log file.
106   */
107 function Logger() {
108
109         if( Logger.logger != null ) { return Logger.logger }
110
111         var config = new Config();
112         this.log_level = config.get_value( "system/log_level" );
113
114         this.stdout_log = config.get_value( "system/stdout_log" );
115
116         if( ! this.stdout_log || this.stdout_log < 0 || this.stdout_log > 2 ) {
117                 throw new oils_ex_config( "stdout_log setting is invalid: " + this.stdout_log + 
118                                 ". Should be 0, 1, or 2." );
119         }
120
121         // ------------------------------------------------------------------
122         // Load up all of the log files
123         // ------------------------------------------------------------------
124         var transport_file = config.get_value( "logs/transport" );
125         if( transport_file == null ) {
126                 throw new oils_ex_config( "Unable to load transport log file: 'logs/transport'" );
127         }
128
129         var debug_file = config.get_value( "logs/debug" );
130         if( debug_file == null ) {
131                 throw new oils_ex_config( "Unable to load debug log file: 'logs/debug'" );
132         }
133         
134         var error_file = config.get_value( "logs/error" );
135         if( error_file == null ) {
136                 throw new oils_ex_config( "Unable to load debug log file: 'logs/error'" );
137         }
138
139
140         // ------------------------------------------------------------------
141         // Build the file objects
142         // ------------------------------------------------------------------
143         var transport_file_obj = Logger.get_log_file( transport_file );
144
145         var debug_file_obj = Logger.get_log_file( debug_file );
146
147         var error_file_obj = Logger.get_log_file( error_file );
148
149
150         // ------------------------------------------------------------------
151         // Build all of the file stream objects
152         // ------------------------------------------------------------------
153         this.transport_stream = Components.classes["@mozilla.org/network/file-output-stream;1"]
154                         .createInstance(Components.interfaces.nsIFileOutputStream);
155
156         this.debug_stream = Components.classes["@mozilla.org/network/file-output-stream;1"]
157                         .createInstance(Components.interfaces.nsIFileOutputStream);
158
159         this.error_stream = Components.classes["@mozilla.org/network/file-output-stream;1"]
160                         .createInstance(Components.interfaces.nsIFileOutputStream);
161
162         // ------------------------------------------------------------------
163         // Init all of the streams
164         // use 0x02 | 0x10 to open file for appending.
165         // ------------------------------------------------------------------
166         this.transport_stream.init(transport_file_obj,  0x02 | 0x10 | 0x08, 0664, 0 ); 
167         this.debug_stream.init( debug_file_obj,                 0x02 | 0x10 | 0x08, 0664, 0 ); 
168         this.error_stream.init( error_file_obj,                 0x02 | 0x10 | 0x08, 0664, 0 ); 
169
170         Logger.logger = this;
171
172 }
173
174 /** Internal.  Returns a XPCOM nsIFile object for the log file we're interested in */
175 Logger.get_log_file = function( log_name ) {
176
177         var dirService = Components.classes["@mozilla.org/file/directory_service;1"].
178                 getService( Components.interfaces.nsIProperties );
179
180         logFile = dirService.get( "AChrom",  Components.interfaces.nsIFile );
181         logFile.append("evergreen");
182         logFile.append("content");
183         logFile.append("log");
184         logFile.append( log_name );
185
186         if( ! logFile.exists() ) {
187                 logFile.create( 0, 0640 );
188         }
189
190         return logFile;
191 }
192
193
194
195 /** Internal. Builds a log message complete with data, etc. */
196 Logger.prototype.build_string = function( message, level ) {
197
198         if( ! (message && level) ) { return null; }
199
200         var lev = "INFO";
201         if( level == Logger.ERROR ) { lev = "ERROR"; }
202         if( level == Logger.DEBUG ) { lev = "DEBUG"; }
203
204         var date                = new Date();
205         var year                = date.getYear();
206         year += 1900;
207
208         var month       = ""+date.getMonth();
209         if(month.length==1) {month="0"+month;}
210         var day         = ""+date.getDate();
211         if(day.length==1) {day="0"+day;}
212         var hour                = ""+date.getHours();
213         if(hour.length== 1){hour="0"+hour;}
214         var min         = ""+date.getMinutes();
215         if(min.length==1){min="0"+min;}
216         var sec         = ""+date.getSeconds();
217         if(sec.length==1){sec="0"+sec;}
218         var mil         = ""+date.getMilliseconds();
219         if(mil.length==1){sec="0"+sec;}
220
221         var date_string = year + "-" + month + "-" + day + " " + 
222                 hour + ":" + min + ":" + sec + "." + mil;
223
224         var str_array = message.split('\n');
225         var ret_array = new Array();
226         for( var i in str_array ) {
227                 ret_str = "[" + date_string +  "] " + lev + " " + str_array[i] + "\n";
228                 ret_array.push( ret_str );
229         }
230
231         var line = "-------------------------\n";
232         ret_array.unshift( line );
233
234         return ret_array;
235 }
236
237 /** Internal. Does the actual writing */
238 Logger.prototype._log = function( data, stream, level ) {
239
240         if( ! data ) { return; }
241         if( ! stream ) { 
242                 throw oils_ex_logger( "No file stream open for log message: " + data ); 
243         }
244         if( ! level ) { level = Logger.DEBUG; }
245
246         if( level > this.log_level ) { return; }
247         var str_array = this.build_string( data, level );
248         if( ! str_array ) { return; }
249
250         for( var i in str_array ) {
251                 if( this.stdout_log > 0 ) { dump( str_array[i] ); }
252                 if( this.stdout_log < 2 ) { stream.write( str_array[i], str_array[i].length ); }
253         }
254
255         // write errors to the error log if they were destined for anywhere else
256         if( level == Logger.ERROR && stream != this.error_stream ) {
257                 for( var i in str_array ) {
258                         if( this.stdout_log > 0 ) { dump( str_array[i] ); }
259                         if( this.stdout_log < 2 ) { this.error_stream.write( str_array[i], str_array[i].length ); }
260                 }
261         }
262 }
263         
264
265
266 /** Writes the message to the error log */
267 Logger.prototype.error = function( message, level ) {
268         this._log( message, this.error_stream, level );
269 }
270
271
272 /** Writes to the debug log */
273 Logger.prototype.debug = function( message, level ) {
274         this._log( message, this.debug_stream, level );
275 }
276
277
278 /** Writes to the transport log */
279 Logger.prototype.transport = function( message, level ) {
280         this._log( message, this.transport_stream, level );
281 }