Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
15747 anikendra 1
/*
2
 *
3
 * Licensed to the Apache Software Foundation (ASF) under one
4
 * or more contributor license agreements.  See the NOTICE file
5
 * distributed with this work for additional information
6
 * regarding copyright ownership.  The ASF licenses this file
7
 * to you under the Apache License, Version 2.0 (the
8
 * "License"); you may not use this file except in compliance
9
 * with the License.  You may obtain a copy of the License at
10
 *
11
 *   http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing,
14
 * software distributed under the License is distributed on an
15
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
 * KIND, either express or implied.  See the License for the
17
 * specific language governing permissions and limitations
18
 * under the License.
19
 *
20
*/
21
 
22
//------------------------------------------------------------------------------
23
// The logger module exports the following properties/functions:
24
//
25
// LOG                          - constant for the level LOG
26
// ERROR                        - constant for the level ERROR
27
// WARN                         - constant for the level WARN
28
// INFO                         - constant for the level INFO
29
// DEBUG                        - constant for the level DEBUG
30
// logLevel()                   - returns current log level
31
// logLevel(value)              - sets and returns a new log level
32
// useConsole()                 - returns whether logger is using console
33
// useConsole(value)            - sets and returns whether logger is using console
34
// log(message,...)             - logs a message at level LOG
35
// error(message,...)           - logs a message at level ERROR
36
// warn(message,...)            - logs a message at level WARN
37
// info(message,...)            - logs a message at level INFO
38
// debug(message,...)           - logs a message at level DEBUG
39
// logLevel(level,message,...)  - logs a message specified level
40
//
41
//------------------------------------------------------------------------------
42
 
43
var logger = exports;
44
 
45
var exec    = require('cordova/exec');
46
var utils   = require('cordova/utils');
47
 
48
var UseConsole   = false;
49
var UseLogger    = true;
50
var Queued       = [];
51
var DeviceReady  = false;
52
var CurrentLevel;
53
 
54
var originalConsole = console;
55
 
56
/**
57
 * Logging levels
58
 */
59
 
60
var Levels = [
61
    "LOG",
62
    "ERROR",
63
    "WARN",
64
    "INFO",
65
    "DEBUG"
66
];
67
 
68
/*
69
 * add the logging levels to the logger object and
70
 * to a separate levelsMap object for testing
71
 */
72
 
73
var LevelsMap = {};
74
for (var i=0; i<Levels.length; i++) {
75
    var level = Levels[i];
76
    LevelsMap[level] = i;
77
    logger[level]    = level;
78
}
79
 
80
CurrentLevel = LevelsMap.WARN;
81
 
82
/**
83
 * Getter/Setter for the logging level
84
 *
85
 * Returns the current logging level.
86
 *
87
 * When a value is passed, sets the logging level to that value.
88
 * The values should be one of the following constants:
89
 *    logger.LOG
90
 *    logger.ERROR
91
 *    logger.WARN
92
 *    logger.INFO
93
 *    logger.DEBUG
94
 *
95
 * The value used determines which messages get printed.  The logging
96
 * values above are in order, and only messages logged at the logging
97
 * level or above will actually be displayed to the user.  E.g., the
98
 * default level is WARN, so only messages logged with LOG, ERROR, or
99
 * WARN will be displayed; INFO and DEBUG messages will be ignored.
100
 */
101
logger.level = function (value) {
102
    if (arguments.length) {
103
        if (LevelsMap[value] === null) {
104
            throw new Error("invalid logging level: " + value);
105
        }
106
        CurrentLevel = LevelsMap[value];
107
    }
108
 
109
    return Levels[CurrentLevel];
110
};
111
 
112
/**
113
 * Getter/Setter for the useConsole functionality
114
 *
115
 * When useConsole is true, the logger will log via the
116
 * browser 'console' object.
117
 */
118
logger.useConsole = function (value) {
119
    if (arguments.length) UseConsole = !!value;
120
 
121
    if (UseConsole) {
122
        if (typeof console == "undefined") {
123
            throw new Error("global console object is not defined");
124
        }
125
 
126
        if (typeof console.log != "function") {
127
            throw new Error("global console object does not have a log function");
128
        }
129
 
130
        if (typeof console.useLogger == "function") {
131
            if (console.useLogger()) {
132
                throw new Error("console and logger are too intertwingly");
133
            }
134
        }
135
    }
136
 
137
    return UseConsole;
138
};
139
 
140
/**
141
 * Getter/Setter for the useLogger functionality
142
 *
143
 * When useLogger is true, the logger will log via the
144
 * native Logger plugin.
145
 */
146
logger.useLogger = function (value) {
147
    // Enforce boolean
148
    if (arguments.length) UseLogger = !!value;
149
    return UseLogger;
150
};
151
 
152
/**
153
 * Logs a message at the LOG level.
154
 *
155
 * Parameters passed after message are used applied to
156
 * the message with utils.format()
157
 */
158
logger.log   = function(message) { logWithArgs("LOG",   arguments); };
159
 
160
/**
161
 * Logs a message at the ERROR level.
162
 *
163
 * Parameters passed after message are used applied to
164
 * the message with utils.format()
165
 */
166
logger.error = function(message) { logWithArgs("ERROR", arguments); };
167
 
168
/**
169
 * Logs a message at the WARN level.
170
 *
171
 * Parameters passed after message are used applied to
172
 * the message with utils.format()
173
 */
174
logger.warn  = function(message) { logWithArgs("WARN",  arguments); };
175
 
176
/**
177
 * Logs a message at the INFO level.
178
 *
179
 * Parameters passed after message are used applied to
180
 * the message with utils.format()
181
 */
182
logger.info  = function(message) { logWithArgs("INFO",  arguments); };
183
 
184
/**
185
 * Logs a message at the DEBUG level.
186
 *
187
 * Parameters passed after message are used applied to
188
 * the message with utils.format()
189
 */
190
logger.debug = function(message) { logWithArgs("DEBUG", arguments); };
191
 
192
// log at the specified level with args
193
function logWithArgs(level, args) {
194
    args = [level].concat([].slice.call(args));
195
    logger.logLevel.apply(logger, args);
196
}
197
 
198
// return the correct formatString for an object
199
function formatStringForMessage(message) {
200
    return (typeof message === "string") ? "" : "%o"; 
201
}
202
 
203
/**
204
 * Logs a message at the specified level.
205
 *
206
 * Parameters passed after message are used applied to
207
 * the message with utils.format()
208
 */
209
logger.logLevel = function(level /* , ... */) {
210
    // format the message with the parameters
211
    var formatArgs = [].slice.call(arguments, 1);
212
    var fmtString = formatStringForMessage(formatArgs[0]);
213
    if (fmtString.length > 0){
214
        formatArgs.unshift(fmtString); // add formatString
215
    }
216
 
217
    var message    = logger.format.apply(logger.format, formatArgs);
218
 
219
    if (LevelsMap[level] === null) {
220
        throw new Error("invalid logging level: " + level);
221
    }
222
 
223
    if (LevelsMap[level] > CurrentLevel) return;
224
 
225
    // queue the message if not yet at deviceready
226
    if (!DeviceReady && !UseConsole) {
227
        Queued.push([level, message]);
228
        return;
229
    }
230
 
231
    // Log using the native logger if that is enabled
232
    if (UseLogger) {
233
        exec(null, null, "Console", "logLevel", [level, message]);
234
    }
235
 
236
    // Log using the console if that is enabled
237
    if (UseConsole) {
238
        // make sure console is not using logger
239
        if (console.useLogger()) {
240
            throw new Error("console and logger are too intertwingly");
241
        }
242
 
243
        // log to the console
244
        switch (level) {
245
            case logger.LOG:   originalConsole.log(message); break;
246
            case logger.ERROR: originalConsole.log("ERROR: " + message); break;
247
            case logger.WARN:  originalConsole.log("WARN: "  + message); break;
248
            case logger.INFO:  originalConsole.log("INFO: "  + message); break;
249
            case logger.DEBUG: originalConsole.log("DEBUG: " + message); break;
250
        }
251
    }
252
};
253
 
254
 
255
/**
256
 * Formats a string and arguments following it ala console.log()
257
 *
258
 * Any remaining arguments will be appended to the formatted string.
259
 *
260
 * for rationale, see FireBug's Console API:
261
 *    http://getfirebug.com/wiki/index.php/Console_API
262
 */
263
logger.format = function(formatString, args) {
264
    return __format(arguments[0], [].slice.call(arguments,1)).join(' ');
265
};
266
 
267
 
268
//------------------------------------------------------------------------------
269
/**
270
 * Formats a string and arguments following it ala vsprintf()
271
 *
272
 * format chars:
273
 *   %j - format arg as JSON
274
 *   %o - format arg as JSON
275
 *   %c - format arg as ''
276
 *   %% - replace with '%'
277
 * any other char following % will format it's
278
 * arg via toString().
279
 *
280
 * Returns an array containing the formatted string and any remaining
281
 * arguments.
282
 */
283
function __format(formatString, args) {
284
    if (formatString === null || formatString === undefined) return [""];
285
    if (arguments.length == 1) return [formatString.toString()];
286
 
287
    if (typeof formatString != "string")
288
        formatString = formatString.toString();
289
 
290
    var pattern = /(.*?)%(.)(.*)/;
291
    var rest    = formatString;
292
    var result  = [];
293
 
294
    while (args.length) {
295
        var match = pattern.exec(rest);
296
        if (!match) break;
297
 
298
        var arg   = args.shift();
299
        rest = match[3];
300
        result.push(match[1]);
301
 
302
        if (match[2] == '%') {
303
            result.push('%');
304
            args.unshift(arg);
305
            continue;
306
        }
307
 
308
        result.push(__formatted(arg, match[2]));
309
    }
310
 
311
    result.push(rest);
312
 
313
    var remainingArgs = [].slice.call(args);
314
    remainingArgs.unshift(result.join(''));
315
    return remainingArgs;
316
}
317
 
318
function __formatted(object, formatChar) {
319
 
320
    try {
321
        switch(formatChar) {
322
            case 'j':
323
            case 'o': return JSON.stringify(object);
324
            case 'c': return '';
325
        }
326
    }
327
    catch (e) {
328
        return "error JSON.stringify()ing argument: " + e;
329
    }
330
 
331
    if ((object === null) || (object === undefined)) {
332
        return Object.prototype.toString.call(object);
333
    }
334
 
335
    return object.toString();
336
}
337
 
338
 
339
//------------------------------------------------------------------------------
340
// when deviceready fires, log queued messages
341
logger.__onDeviceReady = function() {
342
    if (DeviceReady) return;
343
 
344
    DeviceReady = true;
345
 
346
    for (var i=0; i<Queued.length; i++) {
347
        var messageArgs = Queued[i];
348
        logger.logLevel(messageArgs[0], messageArgs[1]);
349
    }
350
 
351
    Queued = null;
352
};
353
 
354
// add a deviceready event to log queued messages
355
document.addEventListener("deviceready", logger.__onDeviceReady, false);