jlog-rails 0.1.3 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/README.md +8 -1
- data/Rakefile +11 -1
- data/app/controllers/jlog/ajax_controller.rb +4 -4
- data/jlog-rails.gemspec +1 -0
- data/lib/jlog/version.rb +1 -1
- data/test/ajax-appender-test.js +22 -0
- data/test/buster.js +28 -0
- data/test/lib/jquery-1.9.1.min.js +5 -0
- data/test/lib/underscore.js +1226 -0
- data/test/logger-test.js +49 -0
- data/test/pattern-layout-test.js +37 -0
- data/vendor/assets/javascripts/appender.js +93 -0
- data/vendor/assets/javascripts/appenders/ajax.js +151 -0
- data/vendor/assets/javascripts/appenders/console.js +20 -0
- data/vendor/assets/javascripts/jlog.js +11 -236
- data/vendor/assets/javascripts/layout.js +216 -0
- data/vendor/assets/javascripts/layouts/pattern.js +184 -0
- data/vendor/assets/javascripts/levels.js +35 -0
- data/vendor/assets/javascripts/logger.js +370 -0
- data/vendor/assets/javascripts/logging_event.js +81 -0
- data/vendor/assets/javascripts/mount.js +4 -0
- metadata +38 -3
@@ -0,0 +1,216 @@
|
|
1
|
+
JLog.Layout = function() {};
|
2
|
+
/*
|
3
|
+
Class: Layout
|
4
|
+
|
5
|
+
Abstract class for message formatting.
|
6
|
+
*/
|
7
|
+
JLog.Layout.prototype = {
|
8
|
+
defaults: {
|
9
|
+
loggerKey: "logger",
|
10
|
+
timeStampKey: "timestamp",
|
11
|
+
millisecondsKey: "milliseconds",
|
12
|
+
levelKey: "level",
|
13
|
+
messageKey: "message",
|
14
|
+
exceptionKey: "exception",
|
15
|
+
urlKey: "url"
|
16
|
+
},
|
17
|
+
loggerKey: "logger",
|
18
|
+
timeStampKey: "timestamp",
|
19
|
+
millisecondsKey: "milliseconds",
|
20
|
+
levelKey: "level",
|
21
|
+
messageKey: "message",
|
22
|
+
exceptionKey: "exception",
|
23
|
+
urlKey: "url",
|
24
|
+
/*
|
25
|
+
Property: batchHeader
|
26
|
+
|
27
|
+
Header of batch output.
|
28
|
+
|
29
|
+
See Also:
|
30
|
+
<allowBatching>, <batchFooter>, <batchSeparator>
|
31
|
+
*/
|
32
|
+
batchHeader: "",
|
33
|
+
/*
|
34
|
+
Property: batchFooter
|
35
|
+
|
36
|
+
Footer of batch output.
|
37
|
+
|
38
|
+
See Also:
|
39
|
+
<allowBatching>, <batchHeader>, <batchSeparator>
|
40
|
+
*/
|
41
|
+
batchFooter: "",
|
42
|
+
/*
|
43
|
+
Property: batchSeparator
|
44
|
+
|
45
|
+
Separator of batch output.
|
46
|
+
|
47
|
+
See Also:
|
48
|
+
<allowBatching>, <batchHeader>, <batchFooter>
|
49
|
+
*/
|
50
|
+
batchSeparator: "",
|
51
|
+
/*
|
52
|
+
Property: useTimeStampsInMilliseconds
|
53
|
+
|
54
|
+
If timestamp should be outputted in milliseconds.
|
55
|
+
*/
|
56
|
+
useTimeStampsInMilliseconds: null,
|
57
|
+
|
58
|
+
/*
|
59
|
+
Method: format
|
60
|
+
|
61
|
+
Formats log message into a string. Has to be overloaded by derivative classes.
|
62
|
+
|
63
|
+
Parameters:
|
64
|
+
logMessage - Log Message to format.
|
65
|
+
|
66
|
+
Returns:
|
67
|
+
Message formatted as string.
|
68
|
+
*/
|
69
|
+
format: function(logMessage) {
|
70
|
+
JLog.handleError("Layout.format: layout supplied has no format() method");
|
71
|
+
},
|
72
|
+
|
73
|
+
/*
|
74
|
+
Method: getContentType
|
75
|
+
|
76
|
+
Used to set content type for network sending.
|
77
|
+
|
78
|
+
Returns:
|
79
|
+
Content-Type header value.
|
80
|
+
*/
|
81
|
+
getContentType: function() {
|
82
|
+
return "text/plain";
|
83
|
+
},
|
84
|
+
|
85
|
+
/*
|
86
|
+
Method: allowBatching
|
87
|
+
|
88
|
+
If formatted messages can be send in a batch. If true, messages will be send in format:
|
89
|
+
batchHeader+MESSAGES.join(batchSeparator)+batchFooter
|
90
|
+
|
91
|
+
Returns:
|
92
|
+
Boolean
|
93
|
+
|
94
|
+
See Also:
|
95
|
+
<batchHeader>, <batchFooter>, <batchSeparator>
|
96
|
+
*/
|
97
|
+
allowBatching: function() {
|
98
|
+
return true;
|
99
|
+
},
|
100
|
+
|
101
|
+
/*
|
102
|
+
Method: getTimeStampValue
|
103
|
+
|
104
|
+
Returns string representation of time of event occurrence in seconds or milliseconds, depending on configuration.
|
105
|
+
|
106
|
+
Parameters:
|
107
|
+
loggingEvent - <LoggingEvent> to fetch timestamp.
|
108
|
+
*/
|
109
|
+
getTimeStampValue: function(loggingEvent) {
|
110
|
+
return this.useTimeStampsInMilliseconds() ?
|
111
|
+
loggingEvent.timeStampInMilliseconds : loggingEvent.timeStampInSeconds;
|
112
|
+
},
|
113
|
+
|
114
|
+
/*
|
115
|
+
Method: getDataValues
|
116
|
+
|
117
|
+
Builds the map of log event environment.
|
118
|
+
|
119
|
+
Parameters:
|
120
|
+
loggingEvent - <LoggingEvent> to fetch data from.
|
121
|
+
combineMessages - Boolean, if messages should be combined into single String, or Array is required.
|
122
|
+
*/
|
123
|
+
getDataValues: function(loggingEvent, combineMessages) {
|
124
|
+
var dataValues = [
|
125
|
+
[this.loggerKey, loggingEvent.logger.name],
|
126
|
+
[this.timeStampKey, this.getTimeStampValue(loggingEvent)],
|
127
|
+
[this.levelKey, loggingEvent.level.name],
|
128
|
+
[this.urlKey, window.location.href],
|
129
|
+
[this.messageKey, combineMessages ? loggingEvent.getCombinedMessages() : loggingEvent.messages]
|
130
|
+
];
|
131
|
+
if(!this.useTimeStampsInMilliseconds()) {
|
132
|
+
dataValues.push([this.millisecondsKey, loggingEvent.milliseconds]);
|
133
|
+
}
|
134
|
+
if(loggingEvent.exception) {
|
135
|
+
dataValues.push([this.exceptionKey, getExceptionStringRep(loggingEvent.exception)]);
|
136
|
+
}
|
137
|
+
if(this.hasCustomFields()) {
|
138
|
+
for(var i = 0, len = this.customFields.length; i < len; i++) {
|
139
|
+
var val = this.customFields[i].value;
|
140
|
+
|
141
|
+
// Check if the value is a function. If so, execute it, passing it the
|
142
|
+
// current layout and the logging event
|
143
|
+
try {
|
144
|
+
if(typeof val === "function")
|
145
|
+
val = val(this, loggingEvent);
|
146
|
+
} catch(e) {
|
147
|
+
JLog.handleError(e);
|
148
|
+
val = "[Exception during evaluating]"
|
149
|
+
}
|
150
|
+
|
151
|
+
dataValues.push([this.customFields[i].name, val]);
|
152
|
+
}
|
153
|
+
}
|
154
|
+
return dataValues;
|
155
|
+
},
|
156
|
+
|
157
|
+
/*
|
158
|
+
Method: setKeys
|
159
|
+
|
160
|
+
Sets key names for standard environment variables.
|
161
|
+
|
162
|
+
Parameters:
|
163
|
+
loggerKey - key for <Logger> name value
|
164
|
+
timeStampKey - key for timestamp value
|
165
|
+
levelKey - key for event <Level> value
|
166
|
+
messageKey - key for message value(s)
|
167
|
+
exceptionKey - key for exception value
|
168
|
+
urlKey - key for URL value
|
169
|
+
millisecondsKey - key for timestamp value in milliseconds
|
170
|
+
*/
|
171
|
+
setKeys: function(loggerKey, timeStampKey, levelKey, messageKey,
|
172
|
+
exceptionKey, urlKey, millisecondsKey) {
|
173
|
+
this.loggerKey = extractStringFromParam(loggerKey, this.defaults.loggerKey);
|
174
|
+
this.timeStampKey = extractStringFromParam(timeStampKey, this.defaults.timeStampKey);
|
175
|
+
this.levelKey = extractStringFromParam(levelKey, this.defaults.levelKey);
|
176
|
+
this.messageKey = extractStringFromParam(messageKey, this.defaults.messageKey);
|
177
|
+
this.exceptionKey = extractStringFromParam(exceptionKey, this.defaults.exceptionKey);
|
178
|
+
this.urlKey = extractStringFromParam(urlKey, this.defaults.urlKey);
|
179
|
+
this.millisecondsKey = extractStringFromParam(millisecondsKey, this.defaults.millisecondsKey);
|
180
|
+
},
|
181
|
+
|
182
|
+
/*
|
183
|
+
Method: setCustomField
|
184
|
+
|
185
|
+
Sets custom variable of the layout.
|
186
|
+
|
187
|
+
Parameters:
|
188
|
+
name - Key for custom field
|
189
|
+
value - Value for custom field
|
190
|
+
*/
|
191
|
+
setCustomField: function(name, value) {
|
192
|
+
var fieldUpdated = false;
|
193
|
+
for (var i = 0, len = this.customFields.length; i < len; i++) {
|
194
|
+
if (this.customFields[i].name === name) {
|
195
|
+
this.customFields[i].value = value;
|
196
|
+
fieldUpdated = true;
|
197
|
+
}
|
198
|
+
}
|
199
|
+
if (!fieldUpdated) {
|
200
|
+
this.customFields.push({"name": name, "value": value});
|
201
|
+
}
|
202
|
+
},
|
203
|
+
|
204
|
+
/*
|
205
|
+
Method: hasCustomFields
|
206
|
+
|
207
|
+
Checks, if there are any custom fields.
|
208
|
+
*/
|
209
|
+
hasCustomFields: function() {
|
210
|
+
return (this.customFields.length > 0);
|
211
|
+
},
|
212
|
+
|
213
|
+
toString: function() {
|
214
|
+
JLog.handleError("Layout.toString: all layouts must override this method");
|
215
|
+
}
|
216
|
+
};
|
@@ -0,0 +1,184 @@
|
|
1
|
+
(function() {
|
2
|
+
var newLine = "\n";
|
3
|
+
|
4
|
+
/*
|
5
|
+
Class: PatternLayout
|
6
|
+
|
7
|
+
Pattern based layout.
|
8
|
+
*/
|
9
|
+
|
10
|
+
/*
|
11
|
+
Constructor: PatternLayout
|
12
|
+
|
13
|
+
Initializes Pattern Layout. Recognizes patterns like %[padding][trunctaion](type)[specifier], where type can be:
|
14
|
+
- *a* - array of messages.
|
15
|
+
- *m* - prints all the messages. Objects are dumped to the _specifier_ depth.
|
16
|
+
- *c* - prints logger name
|
17
|
+
- *d* - prints log event date
|
18
|
+
- *f* - prints custom field defined by _specifier_
|
19
|
+
- *n* - prints new line
|
20
|
+
- *p* - prints log event level name
|
21
|
+
- *r* - prints time in seconds since JLog startup
|
22
|
+
- *%* - prints % sign
|
23
|
+
|
24
|
+
Parameters:
|
25
|
+
pattern - (optional) String format
|
26
|
+
*/
|
27
|
+
function PatternLayout(pattern) {
|
28
|
+
if(pattern) this.pattern = pattern;
|
29
|
+
else this.pattern = PatternLayout.DEFAULT_CONVERSION_PATTERN;
|
30
|
+
this.customFields = [];
|
31
|
+
}
|
32
|
+
|
33
|
+
/*
|
34
|
+
Constant: TTCC_CONVERSION_PATTERN
|
35
|
+
|
36
|
+
Usual verbose pattern.
|
37
|
+
*/
|
38
|
+
PatternLayout.TTCC_CONVERSION_PATTERN = "%r %p %c - %m%n";
|
39
|
+
|
40
|
+
/*
|
41
|
+
Constant: DEFAULT_CONVERSION_PATTERN
|
42
|
+
|
43
|
+
Default concise pattern.
|
44
|
+
*/
|
45
|
+
PatternLayout.DEFAULT_CONVERSION_PATTERN = "%m%n";
|
46
|
+
|
47
|
+
PatternLayout.prototype = new JLog.Layout();
|
48
|
+
|
49
|
+
/*
|
50
|
+
Method: format
|
51
|
+
|
52
|
+
Formats event into string.
|
53
|
+
|
54
|
+
Parameters:
|
55
|
+
loggingEvent - <LoggingEvent> to format
|
56
|
+
*/
|
57
|
+
PatternLayout.prototype.format = function(loggingEvent) {
|
58
|
+
var regex = /%(-?[0-9]+)?(\.?[0-9]+)?([acdfmMnpr%])(\{([^\}]+)\})?|([^%]+)/;
|
59
|
+
var formattedString = "";
|
60
|
+
var result;
|
61
|
+
var searchString = this.pattern;
|
62
|
+
|
63
|
+
// Cannot use regex global flag since it doesn't work with exec in IE5
|
64
|
+
while ((result = regex.exec(searchString))) {
|
65
|
+
var matchedString = result[0];
|
66
|
+
var padding = result[1];
|
67
|
+
var truncation = result[2];
|
68
|
+
var conversionCharacter = result[3];
|
69
|
+
var specifier = result[5];
|
70
|
+
var text = result[6];
|
71
|
+
|
72
|
+
// Check if the pattern matched was just normal text
|
73
|
+
if (text) {
|
74
|
+
formattedString += "" + text;
|
75
|
+
} else {
|
76
|
+
// Create a raw replacement string based on the conversion
|
77
|
+
// character and specifier
|
78
|
+
var replacement = "";
|
79
|
+
switch(conversionCharacter) {
|
80
|
+
case "a": // Array of messages
|
81
|
+
case "m": // Message
|
82
|
+
var depth = 0;
|
83
|
+
if (specifier) {
|
84
|
+
depth = parseInt(specifier, 10);
|
85
|
+
if (isNaN(depth)) {
|
86
|
+
handleError("PatternLayout.format: invalid specifier '" +
|
87
|
+
specifier + "' for conversion character '" + conversionCharacter +
|
88
|
+
"' - should be a number");
|
89
|
+
depth = 0;
|
90
|
+
}
|
91
|
+
}
|
92
|
+
var messages = (conversionCharacter === "a") ? loggingEvent.messages[0] : loggingEvent.messages;
|
93
|
+
for (var i = 0, len = messages.length; i < len; i++) {
|
94
|
+
if (i > 0 && (replacement.charAt(replacement.length - 1) !== " ")) {
|
95
|
+
replacement += " ";
|
96
|
+
}
|
97
|
+
if (depth === 0) {
|
98
|
+
replacement += messages[i];
|
99
|
+
} else {
|
100
|
+
replacement += formatObjectExpansion(messages[i], depth);
|
101
|
+
}
|
102
|
+
}
|
103
|
+
break;
|
104
|
+
case "c": // Logger name
|
105
|
+
var loggerName = loggingEvent.logger.getName();
|
106
|
+
if (specifier) {
|
107
|
+
var precision = parseInt(specifier, 10);
|
108
|
+
var loggerNameBits = loggingEvent.logger.getName().split(".");
|
109
|
+
if (precision >= loggerNameBits.length) {
|
110
|
+
replacement = loggerName;
|
111
|
+
} else {
|
112
|
+
replacement = loggerNameBits.slice(loggerNameBits.length - precision).join(".");
|
113
|
+
}
|
114
|
+
} else {
|
115
|
+
replacement = loggerName;
|
116
|
+
}
|
117
|
+
break;
|
118
|
+
case "d": // Date
|
119
|
+
replacement = "[date-not-implemented]";
|
120
|
+
break;
|
121
|
+
case "f": // Custom field
|
122
|
+
if (this.hasCustomFields()) {
|
123
|
+
var ff = _.findWhere(this.customFields, {name: specifier});
|
124
|
+
if(!ff) replacement = "[Custom Field not fount: " + specifier + "]";
|
125
|
+
else replacement = ff.value;
|
126
|
+
}
|
127
|
+
break;
|
128
|
+
case "n": // New line
|
129
|
+
replacement = newLine;
|
130
|
+
break;
|
131
|
+
case "p": // Level
|
132
|
+
replacement = loggingEvent.level.name;
|
133
|
+
break;
|
134
|
+
case "r": // Milliseconds since log4javascript startup
|
135
|
+
replacement = "" + (loggingEvent.timeStamp.getTime() - JLog.startup.getTime());
|
136
|
+
break;
|
137
|
+
case "%": // Literal % sign
|
138
|
+
replacement = "%";
|
139
|
+
break;
|
140
|
+
default:
|
141
|
+
replacement = matchedString;
|
142
|
+
break;
|
143
|
+
}
|
144
|
+
// Format the replacement according to any padding or
|
145
|
+
// truncation specified
|
146
|
+
var l;
|
147
|
+
|
148
|
+
// First, truncation
|
149
|
+
if (truncation) {
|
150
|
+
l = parseInt(truncation.substr(1), 10);
|
151
|
+
var strLen = replacement.length;
|
152
|
+
if (l < strLen) {
|
153
|
+
replacement = replacement.substring(strLen - l, strLen);
|
154
|
+
}
|
155
|
+
}
|
156
|
+
// Next, padding
|
157
|
+
if (padding) {
|
158
|
+
if (padding.charAt(0) == "-") {
|
159
|
+
l = parseInt(padding.substr(1), 10);
|
160
|
+
// Right pad with spaces
|
161
|
+
while (replacement.length < l) {
|
162
|
+
replacement += " ";
|
163
|
+
}
|
164
|
+
} else {
|
165
|
+
l = parseInt(padding, 10);
|
166
|
+
// Left pad with spaces
|
167
|
+
while (replacement.length < l) {
|
168
|
+
replacement = " " + replacement;
|
169
|
+
}
|
170
|
+
}
|
171
|
+
}
|
172
|
+
formattedString += replacement;
|
173
|
+
}
|
174
|
+
searchString = searchString.substr(result.index + result[0].length);
|
175
|
+
}
|
176
|
+
return formattedString;
|
177
|
+
};
|
178
|
+
|
179
|
+
PatternLayout.prototype.toString = function() {
|
180
|
+
return "PatternLayout";
|
181
|
+
};
|
182
|
+
|
183
|
+
JLog.PatternLayout = PatternLayout;
|
184
|
+
})(JLog);
|
@@ -0,0 +1,35 @@
|
|
1
|
+
/*
|
2
|
+
Enum: Level
|
3
|
+
|
4
|
+
Levels of messages.
|
5
|
+
|
6
|
+
ALL - Used to mark <Logger> of <Appender> as ones allowing all messages.
|
7
|
+
DEBUG - Minimal priority for message. This one is used for least valuable, and massive messages.
|
8
|
+
INFO - Used to trace the system status. These messages are less aggressive then <Level.DEBUG>.
|
9
|
+
WARN - Something could be better at this time.
|
10
|
+
ERROR - Same as <Level.WARN>, but brakes some part of the system. Has to be fixed.
|
11
|
+
FATAL - Same as <Level.WARN>, but brakes all the system. If not fixed - nothing will work at all.
|
12
|
+
NONE - Used to mark <Logger> of <Appender> as ones blocking all the messages.
|
13
|
+
*/
|
14
|
+
JLog.Level = (function() {
|
15
|
+
function Level(priority, name) {
|
16
|
+
this.priority = priority;
|
17
|
+
this.name = name;
|
18
|
+
};
|
19
|
+
|
20
|
+
Level.prototype = {
|
21
|
+
isGreaterOrEqual: function(otherLevel) {
|
22
|
+
return this.priority >= otherLevel.priority;
|
23
|
+
}
|
24
|
+
};
|
25
|
+
|
26
|
+
Level.ALL = new Level(0, "ALL");
|
27
|
+
Level.DEBUG = new Level(1, "DEBUG");
|
28
|
+
Level.INFO = new Level(2, "INFO");
|
29
|
+
Level.WARN = new Level(3, "WARN");
|
30
|
+
Level.ERROR = new Level(4, "ERROR");
|
31
|
+
Level.FATAL = new Level(5, "FATAL");
|
32
|
+
Level.NONE = new Level(6, "NONE");
|
33
|
+
|
34
|
+
return Level;
|
35
|
+
})();
|