layouts-test.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. "use strict";
  2. var vows = require('vows')
  3. , assert = require('assert');
  4. //used for patternLayout tests.
  5. function test(args, pattern, value) {
  6. var layout = args[0]
  7. , event = args[1]
  8. , tokens = args[2];
  9. assert.equal(layout(pattern, tokens)(event), value);
  10. }
  11. vows.describe('log4js layouts').addBatch({
  12. 'colouredLayout': {
  13. topic: function() {
  14. return require('../lib/layouts').colouredLayout;
  15. },
  16. 'should apply level colour codes to output': function(layout) {
  17. var output = layout({
  18. data: ["nonsense"],
  19. startTime: new Date(2010, 11, 5, 14, 18, 30, 45),
  20. categoryName: "cheese",
  21. level: {
  22. toString: function() { return "ERROR"; }
  23. }
  24. });
  25. assert.equal(output, '\x1B[31m[2010-12-05 14:18:30.045] [ERROR] cheese - \x1B[39mnonsense');
  26. },
  27. 'should support the console.log format for the message': function(layout) {
  28. var output = layout({
  29. data: ["thing %d", 2],
  30. startTime: new Date(2010, 11, 5, 14, 18, 30, 45),
  31. categoryName: "cheese",
  32. level: {
  33. toString: function() { return "ERROR"; }
  34. }
  35. });
  36. assert.equal(output, '\x1B[31m[2010-12-05 14:18:30.045] [ERROR] cheese - \x1B[39mthing 2');
  37. }
  38. },
  39. 'messagePassThroughLayout': {
  40. topic: function() {
  41. return require('../lib/layouts').messagePassThroughLayout;
  42. },
  43. 'should take a logevent and output only the message' : function(layout) {
  44. assert.equal(layout({
  45. data: ["nonsense"],
  46. startTime: new Date(2010, 11, 5, 14, 18, 30, 45),
  47. categoryName: "cheese",
  48. level: {
  49. colour: "green",
  50. toString: function() { return "ERROR"; }
  51. }
  52. }), "nonsense");
  53. },
  54. 'should support the console.log format for the message' : function(layout) {
  55. assert.equal(layout({
  56. data: ["thing %d", 1, "cheese"],
  57. startTime: new Date(2010, 11, 5, 14, 18, 30, 45),
  58. categoryName: "cheese",
  59. level : {
  60. colour: "green",
  61. toString: function() { return "ERROR"; }
  62. }
  63. }), "thing 1 cheese");
  64. },
  65. 'should output the first item even if it is not a string': function(layout) {
  66. assert.equal(layout({
  67. data: [ { thing: 1} ],
  68. startTime: new Date(2010, 11, 5, 14, 18, 30, 45),
  69. categoryName: "cheese",
  70. level: {
  71. colour: "green",
  72. toString: function() { return "ERROR"; }
  73. }
  74. }), "{ thing: 1 }");
  75. },
  76. 'should print the stacks of a passed error objects': function(layout) {
  77. assert.isArray(layout({
  78. data: [ new Error() ],
  79. startTime: new Date(2010, 11, 5, 14, 18, 30, 45),
  80. categoryName: "cheese",
  81. level: {
  82. colour: "green",
  83. toString: function() { return "ERROR"; }
  84. }
  85. }).match(/Error\s+at Object\..*\s+\((.*)test[\\\/]layouts-test\.js\:\d+\:\d+\)\s+at runTest/)
  86. , 'regexp did not return a match');
  87. },
  88. 'with passed augmented errors': {
  89. topic: function(layout){
  90. var e = new Error("My Unique Error Message");
  91. e.augmented = "My Unique attribute value";
  92. e.augObj = { at1: "at2" };
  93. return layout({
  94. data: [ e ],
  95. startTime: new Date(2010, 11, 5, 14, 18, 30, 45),
  96. categoryName: "cheese",
  97. level: {
  98. colour: "green",
  99. toString: function() { return "ERROR"; }
  100. }
  101. });
  102. },
  103. 'should print error the contained error message': function(layoutOutput) {
  104. var m = layoutOutput.match(/\{ \[Error: My Unique Error Message\]/);
  105. assert.isArray(m);
  106. },
  107. 'should print error augmented string attributes': function(layoutOutput) {
  108. var m = layoutOutput.match(/augmented:\s'My Unique attribute value'/);
  109. assert.isArray(m);
  110. },
  111. 'should print error augmented object attributes': function(layoutOutput) {
  112. var m = layoutOutput.match(/augObj:\s\{ at1: 'at2' \}/);
  113. assert.isArray(m);
  114. }
  115. }
  116. },
  117. 'basicLayout': {
  118. topic: function() {
  119. var layout = require('../lib/layouts').basicLayout,
  120. event = {
  121. data: ['this is a test'],
  122. startTime: new Date(2010, 11, 5, 14, 18, 30, 45),
  123. categoryName: "tests",
  124. level: {
  125. toString: function() { return "DEBUG"; }
  126. }
  127. };
  128. return [layout, event];
  129. },
  130. 'should take a logevent and output a formatted string': function(args) {
  131. var layout = args[0], event = args[1];
  132. assert.equal(layout(event), "[2010-12-05 14:18:30.045] [DEBUG] tests - this is a test");
  133. },
  134. 'should output a stacktrace, message if the event has an error attached': function(args) {
  135. var layout = args[0], event = args[1], output, lines,
  136. error = new Error("Some made-up error"),
  137. stack = error.stack.split(/\n/);
  138. event.data = ['this is a test', error];
  139. output = layout(event);
  140. lines = output.split(/\n/);
  141. assert.equal(lines.length - 1, stack.length);
  142. assert.equal(
  143. lines[0],
  144. "[2010-12-05 14:18:30.045] [DEBUG] tests - this is a test [Error: Some made-up error]"
  145. );
  146. for (var i = 1; i < stack.length; i++) {
  147. assert.equal(lines[i+2], stack[i+1]);
  148. }
  149. },
  150. 'should output any extra data in the log event as util.inspect strings': function(args) {
  151. var layout = args[0], event = args[1], output, lines;
  152. event.data = ['this is a test', {
  153. name: 'Cheese',
  154. message: 'Gorgonzola smells.'
  155. }];
  156. output = layout(event);
  157. assert.equal(
  158. output,
  159. "[2010-12-05 14:18:30.045] [DEBUG] tests - this is a test " +
  160. "{ name: 'Cheese', message: 'Gorgonzola smells.' }"
  161. );
  162. }
  163. },
  164. 'patternLayout': {
  165. topic: function() {
  166. var event = {
  167. data: ['this is a test'],
  168. startTime: new Date(2010, 11, 5, 14, 18, 30, 45),
  169. categoryName: "multiple.levels.of.tests",
  170. level: {
  171. toString: function() { return "DEBUG"; }
  172. }
  173. }, layout = require('../lib/layouts').patternLayout
  174. , tokens = {
  175. testString: 'testStringToken',
  176. testFunction: function() { return 'testFunctionToken'; },
  177. fnThatUsesLogEvent: function(logEvent) { return logEvent.level.toString(); }
  178. };
  179. return [layout, event, tokens];
  180. },
  181. 'should default to "time logLevel loggerName - message"': function(args) {
  182. test(args, null, "14:18:30 DEBUG multiple.levels.of.tests - this is a test\n");
  183. },
  184. '%r should output time only': function(args) {
  185. test(args, '%r', '14:18:30');
  186. },
  187. '%p should output the log level': function(args) {
  188. test(args, '%p', 'DEBUG');
  189. },
  190. '%c should output the log category': function(args) {
  191. test(args, '%c', 'multiple.levels.of.tests');
  192. },
  193. '%m should output the log data': function(args) {
  194. test(args, '%m', 'this is a test');
  195. },
  196. '%n should output a new line': function(args) {
  197. test(args, '%n', '\n');
  198. },
  199. '%c should handle category names like java-style package names': function(args) {
  200. test(args, '%c{1}', 'tests');
  201. test(args, '%c{2}', 'of.tests');
  202. test(args, '%c{3}', 'levels.of.tests');
  203. test(args, '%c{4}', 'multiple.levels.of.tests');
  204. test(args, '%c{5}', 'multiple.levels.of.tests');
  205. test(args, '%c{99}', 'multiple.levels.of.tests');
  206. },
  207. '%d should output the date in ISO8601 format': function(args) {
  208. test(args, '%d', '2010-12-05 14:18:30.045');
  209. },
  210. '%d should allow for format specification': function(args) {
  211. test(args, '%d{ISO8601}', '2010-12-05 14:18:30.045');
  212. test(args, '%d{ABSOLUTE}', '14:18:30.045');
  213. test(args, '%d{DATE}', '05 12 2010 14:18:30.045');
  214. test(args, '%d{yyyy MM dd}', '2010 12 05');
  215. test(args, '%d{yyyy MM dd hh mm ss SSS}', '2010 12 05 14 18 30 045');
  216. },
  217. '%% should output %': function(args) {
  218. test(args, '%%', '%');
  219. },
  220. 'should output anything not preceded by % as literal': function(args) {
  221. test(args, 'blah blah blah', 'blah blah blah');
  222. },
  223. 'should output the original string if no replacer matches the token': function(args) {
  224. test(args, '%a{3}', 'a{3}');
  225. },
  226. 'should handle complicated patterns': function(args) {
  227. test(args,
  228. '%m%n %c{2} at %d{ABSOLUTE} cheese %p%n',
  229. 'this is a test\n of.tests at 14:18:30.045 cheese DEBUG\n'
  230. );
  231. },
  232. 'should truncate fields if specified': function(args) {
  233. test(args, '%.4m', 'this');
  234. test(args, '%.7m', 'this is');
  235. test(args, '%.9m', 'this is a');
  236. test(args, '%.14m', 'this is a test');
  237. test(args, '%.2919102m', 'this is a test');
  238. },
  239. 'should pad fields if specified': function(args) {
  240. test(args, '%10p', ' DEBUG');
  241. test(args, '%8p', ' DEBUG');
  242. test(args, '%6p', ' DEBUG');
  243. test(args, '%4p', 'DEBUG');
  244. test(args, '%-4p', 'DEBUG');
  245. test(args, '%-6p', 'DEBUG ');
  246. test(args, '%-8p', 'DEBUG ');
  247. test(args, '%-10p', 'DEBUG ');
  248. },
  249. '%[%r%] should output colored time': function(args) {
  250. test(args, '%[%r%]', '\x1B[36m14:18:30\x1B[39m');
  251. },
  252. '%x{testString} should output the string stored in tokens': function(args) {
  253. test(args, '%x{testString}', 'testStringToken');
  254. },
  255. '%x{testFunction} should output the result of the function stored in tokens': function(args) {
  256. test(args, '%x{testFunction}', 'testFunctionToken');
  257. },
  258. '%x{doesNotExist} should output the string stored in tokens': function(args) {
  259. test(args, '%x{doesNotExist}', '%x{doesNotExist}');
  260. },
  261. '%x{fnThatUsesLogEvent} should be able to use the logEvent': function(args) {
  262. test(args, '%x{fnThatUsesLogEvent}', 'DEBUG');
  263. },
  264. '%x should output the string stored in tokens': function(args) {
  265. test(args, '%x', '%x');
  266. },
  267. },
  268. 'layout makers': {
  269. topic: require('../lib/layouts'),
  270. 'should have a maker for each layout': function(layouts) {
  271. assert.ok(layouts.layout("messagePassThrough"));
  272. assert.ok(layouts.layout("basic"));
  273. assert.ok(layouts.layout("colored"));
  274. assert.ok(layouts.layout("coloured"));
  275. assert.ok(layouts.layout("pattern"));
  276. }
  277. }
  278. }).export(module);