superlogger 0.2.1 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +23 -48
  3. data/lib/superlogger/action_controller_log_subscriber.rb +3 -11
  4. data/lib/superlogger/action_view_log_subscriber.rb +1 -1
  5. data/lib/superlogger/active_record_log_subscriber.rb +5 -3
  6. data/lib/superlogger/logger.rb +13 -27
  7. data/lib/superlogger/superlogger_middleware.rb +8 -9
  8. data/lib/superlogger/version.rb +1 -1
  9. data/lib/superlogger.rb +20 -5
  10. data/test/dummy/app/assets/config/manifest.js +3 -0
  11. data/test/dummy/config/application.rb +3 -2
  12. data/test/superlogger_test.rb +30 -58
  13. metadata +10 -181
  14. data/test/dummy/db/development.sqlite3 +0 -0
  15. data/test/dummy/db/test.sqlite3 +0 -0
  16. data/test/dummy/log/development.log +0 -545
  17. data/test/dummy/log/test.log +0 -1732
  18. data/test/dummy/tmp/cache/assets/sprockets/v3.0/-H/-HJqDF0cY1IQQf6G35SzwnWhdJwbb0rjsilAS1uSnC0.cache +0 -0
  19. data/test/dummy/tmp/cache/assets/sprockets/v3.0/1e/1eeMDHdcXM5QG6315g0Uj656M_FVD0teimYul97xBzQ.cache +0 -1
  20. data/test/dummy/tmp/cache/assets/sprockets/v3.0/38/38YtaoIS3EsFiiaKJPIWZKoxwdIGtUeAuwIBAuuQ8Mg.cache +0 -0
  21. data/test/dummy/tmp/cache/assets/sprockets/v3.0/5L/5Lly_CA8DZvPhQV2jDQx-Y6P_y3Ygra9t5jfSlGhHDA.cache +0 -0
  22. data/test/dummy/tmp/cache/assets/sprockets/v3.0/7J/7JXLU3kClrFYffhxcnNaLGjYz8LFI700NBjNiBOifaU.cache +0 -0
  23. data/test/dummy/tmp/cache/assets/sprockets/v3.0/C_/C_C8IqUQirTZx1bt5Ewm3QJvhVbwm66pxvcH0maphFY.cache +0 -0
  24. data/test/dummy/tmp/cache/assets/sprockets/v3.0/Ch/Ch2bQFHkYziI9Erdkuj8uoPJyw0W2aA5prtYAqlccww.cache +0 -1
  25. data/test/dummy/tmp/cache/assets/sprockets/v3.0/Cq/Cq4V3OyOOk4eTJXISTKVc4MbIHDmq4eu3lSNh85i78k.cache +0 -1
  26. data/test/dummy/tmp/cache/assets/sprockets/v3.0/DS/DSOLSc6A5RVSmvM415eEWAWG_AgOvZcLZOXQjsXyWQA.cache +0 -2
  27. data/test/dummy/tmp/cache/assets/sprockets/v3.0/EC/EC4O6KSVM5bCKFeBl2j8bzAbnhklqssWQ-6XEqM_tC4.cache +0 -0
  28. data/test/dummy/tmp/cache/assets/sprockets/v3.0/Gy/Gyqn3Ja6WbUSqKnvWm9Xw7FIxFqJIPQ88IlgpguMo1s.cache +0 -1
  29. data/test/dummy/tmp/cache/assets/sprockets/v3.0/H3/H3tvaQM-yTy-25oSLlfjToAa74LSJHBDUpji-8C-eLg.cache +0 -0
  30. data/test/dummy/tmp/cache/assets/sprockets/v3.0/Iv/IvDM1j8-H1H6kEjVCsyIW8N2zla-aIp9q_OE9PVZtVw.cache +0 -1
  31. data/test/dummy/tmp/cache/assets/sprockets/v3.0/Jj/JjqPODxMglZzjE6lolNyoEiFCULPe-AH8rndpgamPPk.cache +0 -1
  32. data/test/dummy/tmp/cache/assets/sprockets/v3.0/K9/K9ZheMi0hi4DNLzmDMRnv9A_lOVz33kNImc16Now42o.cache +0 -1
  33. data/test/dummy/tmp/cache/assets/sprockets/v3.0/LH/LHgjtAV8kdldaJ_dX0RCznzjmWYRuLdhU29fZCJ0VmU.cache +0 -1
  34. data/test/dummy/tmp/cache/assets/sprockets/v3.0/Nn/NnUCa7jNYx9HCmEB7E7WPWT00DwaM4IYICy1Ju1jjcs.cache +0 -1
  35. data/test/dummy/tmp/cache/assets/sprockets/v3.0/O5/O5UdaBuHdxmEoYz3AFZsm3rh7MWtRFXwHOryps7b5tE.cache +0 -1
  36. data/test/dummy/tmp/cache/assets/sprockets/v3.0/OI/OI6uxGcnsKavdWTtwDAasU3wPx8QXhzBgV0X2n1KjMQ.cache +0 -0
  37. data/test/dummy/tmp/cache/assets/sprockets/v3.0/Ol/OlBX9JIv9SAOmK2t35x1SYDx1sxCXF0yvqpna3WMyH0.cache +0 -1
  38. data/test/dummy/tmp/cache/assets/sprockets/v3.0/Pg/PgSSsdzJcNT1S4NDynUSIcj_YZXO_IKpcmyafopOamk.cache +0 -0
  39. data/test/dummy/tmp/cache/assets/sprockets/v3.0/SG/SGLQX80_DB28A_mjz_Eh9ZQxVU85Dz1YSRz0Xf3T6qE.cache +0 -1
  40. data/test/dummy/tmp/cache/assets/sprockets/v3.0/T4/T4WYRrwWhIVaINf3NmLDXIAI3bybsjl0y4P1KQgM-Qs.cache +0 -0
  41. data/test/dummy/tmp/cache/assets/sprockets/v3.0/Yr/YrZ0OIHu42cExs1kqngMA6ShVDKhfGmhyW-E9haNo5Y.cache +0 -1
  42. data/test/dummy/tmp/cache/assets/sprockets/v3.0/ZQ/ZQkA-jIm0iNMfDDgK-M4OcgHPKRo-uBuEEowd_5_6Rg.cache +0 -0
  43. data/test/dummy/tmp/cache/assets/sprockets/v3.0/ZU/ZUokoeZcfmoTFE9YAHZRhTgceOUGJTDGH__SCqPfkqU.cache +0 -0
  44. data/test/dummy/tmp/cache/assets/sprockets/v3.0/_I/_IocgQl8XVm84HohovEBj-GxsSeBkOpqN-94yHgY-K8.cache +0 -0
  45. data/test/dummy/tmp/cache/assets/sprockets/v3.0/bJ/bJVgCoQDvMv4iocjEuC3z3WqSeK7LXgxDJ-eXaHl0l4.cache +0 -0
  46. data/test/dummy/tmp/cache/assets/sprockets/v3.0/b_/b_-O1DwVvDk3vPJ-GHDgGWR9Zth9CYblcXbBe6aiTf0.cache +0 -0
  47. data/test/dummy/tmp/cache/assets/sprockets/v3.0/br/brSVWTme0G1yzUMjrDpklxoQetdFLXdF8ZUkYXFX-sE.cache +0 -1
  48. data/test/dummy/tmp/cache/assets/sprockets/v3.0/cI/cIaWfk6Nq6ZAr0fhtHGTBtsRITI5n8IJFZbClZ2tExw.cache +0 -0
  49. data/test/dummy/tmp/cache/assets/sprockets/v3.0/f-/f-gxq-RYinlir2WGpHfXu4C3r6M4aidyokcd7ZnBOao.cache +0 -1
  50. data/test/dummy/tmp/cache/assets/sprockets/v3.0/fE/fEpQwSnNzL1JpFhnElwxvX6YuOxn_vv_QuOTJNrl21M.cache +0 -0
  51. data/test/dummy/tmp/cache/assets/sprockets/v3.0/g3/g3x0V2jnf5A31QMz4xGeQMouu2eChQRpoe0BEWWESeY.cache +0 -1
  52. data/test/dummy/tmp/cache/assets/sprockets/v3.0/gV/gVVPZef0xfm7t9Jyesa7ZVdnpzMpw2QtOyYUoEXO7fk.cache +0 -0
  53. data/test/dummy/tmp/cache/assets/sprockets/v3.0/gZ/gZp3uXMHuYQC4hzCr7bQfetKNdJAtbQmg3so2KpW1Dw.cache +0 -2
  54. data/test/dummy/tmp/cache/assets/sprockets/v3.0/gb/gbunrAFVOHPwl2npUgKv_C3f_qiJnZDd9zG5-h3jrpo.cache +0 -1
  55. data/test/dummy/tmp/cache/assets/sprockets/v3.0/gp/gpiWtnqpufka8lRtMznM6Ko0aWJrcH_j8cfZwdYmzNI.cache +0 -1
  56. data/test/dummy/tmp/cache/assets/sprockets/v3.0/hZ/hZi1k6tpxxCGYxRe7zY74ItcOI8gZrREOpGuA8JSpGg.cache +0 -0
  57. data/test/dummy/tmp/cache/assets/sprockets/v3.0/hl/hlDmEHZNeRDjBO6WJNb8ftVgfvCQubblXCEJw_MO3ow.cache +0 -1
  58. data/test/dummy/tmp/cache/assets/sprockets/v3.0/i7/i7v4b6OSQUj-1r9vUWRiOHjAVksSTpUfilZTpk0ACLc.cache +0 -0
  59. data/test/dummy/tmp/cache/assets/sprockets/v3.0/kz/kzdSvu57G4i6eTuarsZCAfbhbICnkRa0Xhi0b9ua6qk.cache +0 -1
  60. data/test/dummy/tmp/cache/assets/sprockets/v3.0/mv/mvqN6PphkrOOC8zbUEhpC_9E_4ybdO25MRy_gG6dq3Y.cache +0 -1
  61. data/test/dummy/tmp/cache/assets/sprockets/v3.0/nm/nmcUZlKAIwyJ_35Nm9P8pukLeRX5aApP6NFj5MpNPgc.cache +0 -1
  62. data/test/dummy/tmp/cache/assets/sprockets/v3.0/pE/pEhaat2KBd5SrT7szC_8R1_6hK17FTpvoRFkmCRSD3M.cache +0 -0
  63. data/test/dummy/tmp/cache/assets/sprockets/v3.0/rC/rCO5-bHVJ6Y_GsPBmOPUL23pfjvc2Gw2zt_ODmZsygw.cache +0 -1
  64. data/test/dummy/tmp/cache/assets/sprockets/v3.0/rg/RgmbeHiCGDMtbXGovkyp2kHJljF3k6_21IfxBUqa2GQ.cache +0 -0
  65. data/test/dummy/tmp/cache/assets/sprockets/v3.0/rg/rghMLGUpm1Uy3OPgfILHnVwLCycV9Rd9kSpEbxdwVV4.cache +0 -0
  66. data/test/dummy/tmp/cache/assets/sprockets/v3.0/vm/vm9zMjZUFULeJsYWRoDd3cvnEpLGK-E5XTk30_NQTEs.cache +0 -0
  67. data/test/dummy/tmp/cache/assets/sprockets/v3.0/wD/wDDl7jzOUTDgFcG1JlpN6jVHavfzB8Smsjtl3d8WDx0.cache +0 -1
  68. data/test/dummy/tmp/cache/assets/sprockets/v3.0/xd/xdBKQyhEAlDIstGvXw945PWJoEWi23rKuY7elOcWqHc.cache +0 -1
  69. data/test/dummy/tmp/cache/assets/sprockets/v3.0/ys/ysosYWYA283HXmg_f6HoIzLi86SIIm3aVUwWF7tZJHY.cache +0 -0
  70. data/test/dummy/tmp/cache/sprockets/v3.0/-Z_pj4kfRj993e_ypawYQUIDIDKcRe569udVq_1drFs.cache +0 -1
  71. data/test/dummy/tmp/cache/sprockets/v3.0/2G0Z7Q5fvf2xX8ygtwcD9vZq-kwEzoV2MFc1URegs7s.cache +0 -1
  72. data/test/dummy/tmp/cache/sprockets/v3.0/5Lly_CA8DZvPhQV2jDQx-Y6P_y3Ygra9t5jfSlGhHDA.cache +0 -2
  73. data/test/dummy/tmp/cache/sprockets/v3.0/66bWF3byFzdKpXZsrn5Vy9CJBaDlkJKkoyqeLRRbBZY.cache +0 -0
  74. data/test/dummy/tmp/cache/sprockets/v3.0/9NtfUddiu2UU8sqL-bYq-NPAx8NGp5m5AYiAWAcKQQ4.cache +0 -0
  75. data/test/dummy/tmp/cache/sprockets/v3.0/DSOLSc6A5RVSmvM415eEWAWG_AgOvZcLZOXQjsXyWQA.cache +0 -2
  76. data/test/dummy/tmp/cache/sprockets/v3.0/GELqHyWyVR_UvkpZPDb5xjZrCgkKB5G067DYoMwTjEA.cache +0 -0
  77. data/test/dummy/tmp/cache/sprockets/v3.0/Gyqn3Ja6WbUSqKnvWm9Xw7FIxFqJIPQ88IlgpguMo1s.cache +0 -1
  78. data/test/dummy/tmp/cache/sprockets/v3.0/H5fHMceViwaxMKkefsdMmVpBN3rRYZI1obJX5Jn-4jw.cache +0 -1
  79. data/test/dummy/tmp/cache/sprockets/v3.0/IEJfj4Zwfra6y7iF-BOVR9PPIQeL9L5IiZT8MRqpCXg.cache +0 -0
  80. data/test/dummy/tmp/cache/sprockets/v3.0/IordxSS9mOh1mkt2VyfX7Iz4DhZhy73lccOYxcw5aVU.cache +0 -1
  81. data/test/dummy/tmp/cache/sprockets/v3.0/KgQHhqXCaYHJSJEG6JweQVe1a2rC-mHfkrqD9p9taTU.cache +0 -2
  82. data/test/dummy/tmp/cache/sprockets/v3.0/Ki_R5uSCGEm1Jn7TSbJOc3eBMn4Q3_IPLG0r_RRn9lA.cache +0 -1
  83. data/test/dummy/tmp/cache/sprockets/v3.0/NBBjlBjfPdkZkp4G7VCEA9LAeGycMn10CxLbDAbNeHc.cache +0 -0
  84. data/test/dummy/tmp/cache/sprockets/v3.0/OI6uxGcnsKavdWTtwDAasU3wPx8QXhzBgV0X2n1KjMQ.cache +0 -2
  85. data/test/dummy/tmp/cache/sprockets/v3.0/V9m2At1eKJAvbGAFvFTUt8hcdNI-G8xW1AShyPYS4Ys.cache +0 -1
  86. data/test/dummy/tmp/cache/sprockets/v3.0/XsDQ8X8Klh__7HZNZk8sjYzyFg5TmATqo-_UraArzN8.cache +0 -1
  87. data/test/dummy/tmp/cache/sprockets/v3.0/ZtbyFLml01tdqcRh4Ocz6XOkbPpmHM6nFRRYY4Nphpc.cache +0 -1
  88. data/test/dummy/tmp/cache/sprockets/v3.0/_ZNMI9IrCfXNcrwiRGttWiFPcLlCSpkdJSFoLhmUpyg.cache +0 -0
  89. data/test/dummy/tmp/cache/sprockets/v3.0/brSVWTme0G1yzUMjrDpklxoQetdFLXdF8ZUkYXFX-sE.cache +0 -1
  90. data/test/dummy/tmp/cache/sprockets/v3.0/gZp3uXMHuYQC4hzCr7bQfetKNdJAtbQmg3so2KpW1Dw.cache +0 -2
  91. data/test/dummy/tmp/cache/sprockets/v3.0/hZi1k6tpxxCGYxRe7zY74ItcOI8gZrREOpGuA8JSpGg.cache +0 -2
  92. data/test/dummy/tmp/cache/sprockets/v3.0/jqyQL40gGhkqnPg3IttXbq8JGHLONBjR0MlrN9HeIvU.cache +0 -1
  93. data/test/dummy/tmp/cache/sprockets/v3.0/kqQAJDpBuiNJ3XEy8VjtVcyUB9BVlP02oDMdVnlL04w.cache +0 -0
  94. data/test/dummy/tmp/cache/sprockets/v3.0/pEhaat2KBd5SrT7szC_8R1_6hK17FTpvoRFkmCRSD3M.cache +0 -2
  95. data/test/dummy/tmp/cache/sprockets/v3.0/pnW3u_1AN48ig6ngefI89y96xoSlvnJurx-e3J-leoE.cache +0 -2
  96. data/test/dummy/tmp/cache/sprockets/v3.0/q9kUTJTzJpwJJQ8CoWPFc_eCW76RZgB-R2sc4P84y6c.cache +0 -0
  97. data/test/dummy/tmp/cache/sprockets/v3.0/qFlPbNZ3UJs9EnENWVEbNWnrTEcjZkAQUzH55y3Ymi0.cache +0 -1
  98. data/test/dummy/tmp/cache/sprockets/v3.0/r86oWGkKGjcta2GtxqeESX1w_4FX1c_DWHxPWVKP28A.cache +0 -1
  99. data/test/dummy/tmp/cache/sprockets/v3.0/ssS2x0Wl67rwXHaVHsh6CO7ayn9fQ5saIwATKN6O-nI.cache +0 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 95512203bc8b39f0d4924b68d77e97ffc79c26e6
4
- data.tar.gz: 19ae2427a6b9e1df1b85ba7ed252fb0ae98d424e
2
+ SHA256:
3
+ metadata.gz: '082cbc716a6f0432e73617a883fd03584bd8f3de5a1f3f32afd6a48882d05f76'
4
+ data.tar.gz: c85c50a9e182a78c3c281a427b5fd351c4c01b9181dbeffe81a6831bc51f7b39
5
5
  SHA512:
6
- metadata.gz: 73305d6f09e850f0a1534f8836db120bd20bf46a843330b38226d3778cb3044d73d31bc1e5473b5c7308465b3d75062ca8705bc2ce23ded18f2bcd17c2652b3f
7
- data.tar.gz: 25807a67f277bbdfcddf590c705bad9a3ef3eb16cad72c45019db16626fc994fae1ec1e676fda5a0be2369dc637f8cf22798539e11d6c8fe46b0a0127f88133b
6
+ metadata.gz: 7f5eb670792f8cb1abf4a4b3830b7b0e415b9f0849d9339bf8ddce091dc71dd7f2cc455813f7c6ca64fafba40ab8de59f32c6fd1a6c5cec74d24968caecc3624
7
+ data.tar.gz: bc3c65ddb32e7e5eec96de1028d86a12557fda30643797eb71e863db4dac24fcf82dd5434a8c72639a9eb78b1168e60fc4c2dc3fbbd71fffb6a0dcbf08cc3f13
data/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  Superlogger - Machine-readable logging for Rails
6
6
  =======
7
7
 
8
- Rails' default request logging is easy to read for humans but difficult for log aggregators such as Kibana, Graylog and Splunk. Superlogger transforms the logs into key-value pairs for easy parsing and adds useful details like Timestamp, Session ID and Request ID for tracing purposes.
8
+ Rails' default request logging is easy to read for humans but difficult for log aggregators such as Kibana, Graylog and Splunk. Superlogger transforms the logs into JSON for easy parsing and adds useful details like Timestamp, Session ID and Request ID for tracing purposes.
9
9
 
10
10
  Default rails logging:
11
11
  ```sh
@@ -23,34 +23,18 @@ Started GET "/assets/application.self-8f06a73c35179188914ab50e057157639fce1401c1
23
23
 
24
24
  ```
25
25
 
26
- Machine-readable logging with Superlogger:
26
+ With Superlogger:
27
27
  ```sh
28
- # first request
29
- 2016-04-29 17:29:45.841 | 12dc0e484869 | 68d63a8cf920 | I | superlogger_middleware:30 | method=GET | path=/home/index | ip=::1
30
- 2016-04-29 17:29:45.847 | 12dc0e484869 | 68d63a8cf920 | D | action_controller_log_subscriber:9 | controller=HomeController | action=index | params={}
31
- 2016-04-29 17:29:45.852 | 12dc0e484869 | 68d63a8cf920 | D | active_record_log_subscriber:24 | sql=SELECT "somethings".* FROM "somethings" WHERE "somethings"."paper" = ? AND "somethings"."stone" = ? ORDER BY "somethings"."id" ASC LIMIT 1 | params=["123", "456"] | duration=0.13
32
- 2016-04-29 17:29:45.861 | 12dc0e484869 | 68d63a8cf920 | D | action_view_log_subscriber:6 | view=_partial.html.erb | duration=0.2
33
- 2016-04-29 17:29:45.861 | 12dc0e484869 | 68d63a8cf920 | D | action_view_log_subscriber:6 | view=index.html.erb | duration=3.2
34
- 2016-04-29 17:29:45.983 | 12dc0e484869 | 68d63a8cf920 | I | action_controller_log_subscriber:29 | status=200 | total_duration=135.92 | view_duration=130.38 | db_duration=0.33
35
- 2016-04-29 17:29:45.983 | 12dc0e484869 | 68d63a8cf920 | I | superlogger_middleware:30 | method=GET | path=/home/index | total_duration=135.92
36
-
37
- # second request
38
- 2016-04-29 17:39:54.879 | 12dc0e484869 | e463d380fb63 | I | superlogger_middleware:30 | method=GET | path=/home/show | ip=::1
39
- 2016-04-29 17:39:54.879 | 12dc0e484869 | e463d380fb63 | D | action_controller_log_subscriber:9 | controller=HomeController | action=show | params={}
40
- 2016-04-29 17:39:54.882 | 12dc0e484869 | e463d380fb63 | D | action_view_log_subscriber:6 | view=show.html.erb | duration=0.2
41
- 2016-04-29 17:39:54.884 | 12dc0e484869 | e463d380fb63 | I | action_controller_log_subscriber:29 | status=200 | total_duration=4.64 | view_duration=4.55 | db_duration=0.0
42
- 2016-04-29 17:39:54.884 | 12dc0e484869 | e463d380fb63 | I | superlogger_middleware:30 | method=GET | path=/home/index | total_duration=4.64
28
+ {"level":"debug","ts":1590972589.522784,"caller":"superlogger/active_record_log_subscriber:21","sql":"SELECT \"schema_migrations\".\"version\" FROM \"schema_migrations\" ORDER BY \"schema_migrations\".\"version\" ASC","params":[],"duration":0.13}
29
+ {"level":"info","ts":1590972589.526133,"caller":"superlogger/superlogger_middleware:21","session_id":"90e90c75c72c","request_id":"34432478c89b4d8591e02e0169b40a56","method":"GET","path":"/home/index"}
30
+ {"level":"debug","ts":1590972589.546272,"caller":"superlogger/action_controller_log_subscriber:8","session_id":"90e90c75c72c","request_id":"34432478c89b4d8591e02e0169b40a56","controller":"HomeController","action":"index","params":{}}
31
+ {"level":"debug","ts":1590972589.55092,"caller":"superlogger/active_record_log_subscriber:21","session_id":"90e90c75c72c","request_id":"34432478c89b4d8591e02e0169b40a56","sql":"SELECT \"somethings\".* FROM \"somethings\" WHERE \"somethings\".\"paper\" = ? AND \"somethings\".\"stone\" = ? ORDER BY \"somethings\".\"id\" ASC LIMIT ?","params":["123","456","1"],"duration":0.22}
32
+ {"level":"debug","ts":1590972589.574199,"caller":"superlogger/action_view_log_subscriber:6","session_id":"90e90c75c72c","request_id":"34432478c89b4d8591e02e0169b40a56","view":"_partial.html.erb","duration":0.33}
33
+ {"level":"debug","ts":1590972589.574795,"caller":"superlogger/action_view_log_subscriber:6","session_id":"90e90c75c72c","request_id":"34432478c89b4d8591e02e0169b40a56","view":"index.html.erb","duration":2.95}
34
+ {"level":"info","ts":1590972589.61165,"caller":"superlogger/action_controller_log_subscriber:20","session_id":"90e90c75c72c","request_id":"34432478c89b4d8591e02e0169b40a56","view_duration":54.59,"db_duration":0.85}
35
+ {"level":"info","ts":1590972589.611928,"caller":"superlogger/superlogger_middleware:30","session_id":"90e90c75c72c","request_id":"34432478c89b4d8591e02e0169b40a56","method":"GET","path":"/home/index","response_time":85.65,"status":200}
43
36
  ```
44
37
 
45
- ## Features ##
46
- - Timestamp (milliseconds)
47
- - Session ID for logs belonging to the same user session (notice above that both the requests have the same session id)
48
- - Request ID for logs belonging to the same page request (notice above that each request have a different request id)
49
- - Hashes will be logged as key-value pairs automatically
50
- - Requests for assets will not be logged
51
- - File and line numbers
52
- - IP address of request
53
-
54
38
  ## Installation ##
55
39
 
56
40
  Add superlogger to your application's Gemfile
@@ -63,37 +47,28 @@ Execute:
63
47
  $ bundle
64
48
  ```
65
49
 
66
- And add the following in `config/application.rb`
50
+ And add the following in `config/environment/production.rb`
67
51
  ```ruby
68
52
  config.logger = Superlogger::Logger.new(STDOUT)
69
53
  ```
70
54
 
55
+ By default, Superlogger is only enabled in production environment because JSON is easy for machines to parse but difficult for humans to read. To forcefully enable Superlogger in non-production environment, set in `config/application.rb`:
56
+ ```ruby
57
+ Superlogger.enabled = true
58
+ ```
59
+
71
60
  ## Usage ##
72
61
 
73
62
  Log as per normal using `Rails.logger`.
74
63
 
75
64
  ```ruby
76
- class SomeClass
77
- def some_method
78
- Rails.logger.debug foo:'true', bar: 'false'
79
- Rails.logger.info foo:'true', bar: 'false'
80
- Rails.logger.warn foo:'true', bar: 'false'
81
- Rails.logger.error foo:'true', bar: 'false'
82
- Rails.logger.fatal foo:'true', bar: 'false'
83
- end
84
- end
65
+ Rails.logger.info foo:'true', bar: 'false'
66
+ Rails.logger.info "Meatball"
85
67
  ```
86
68
 
87
69
  ## Log Format ##
88
- ```sh
89
- 2015-03-26 23:37:38.086 | 12dc0e484869 | e463d380fb63 | I | action_controller_log_subscriber:29 | status=200 | total_duration=4.64 | view_duration=4.55 | db_duration=0.0
90
- < timestamp > | < session id > | < request id > | < severity > | < file >:< line num > | < data you pass in ... >
91
- < 23 chars > | < 12 chars > | <12 chars > | < 1 char > | < ? chars > | < ? chars >
92
- ```
93
-
94
- ### Severity Levels ###
95
- - **D** - Debug
96
- - **I** - Info
97
- - **W** - Warn
98
- - **E** - Error
99
- - **F** - Fatal
70
+ - `ts` = Unix Epoch timestamp
71
+ - `session_id` = Truncated to 12 characters
72
+ - `request_id` = 32 characters
73
+ - `msg` = If values given is not a hash, it is treated as `{"msg":<value>"}`
74
+ - All duration related fields are in milliseconds
@@ -5,27 +5,19 @@ module Superlogger
5
5
  # start of controller action
6
6
  def start_processing(event)
7
7
  payload = event.payload
8
-
9
- logger.debug controller: payload[:controller], action: payload[:action], params: payload[:params].except(*INTERNAL_PARAMS)
8
+ logger.debug {{ controller: payload[:controller], action: payload[:action], params: payload[:params].except(*INTERNAL_PARAMS) }}
10
9
  end
11
10
 
12
11
  # end of controller action
13
12
  def process_action(event)
14
13
  payload = event.payload
15
- total_duration = event.duration.to_f.round(2)
16
14
  view_duration = payload[:view_runtime].to_f.round(2) if payload.key?(:view_runtime)
17
15
  db_duration = payload[:db_runtime].to_f.round(2) if payload.key?(:db_runtime)
18
16
 
19
17
  if payload[:exception]
20
- status = ActionDispatch::ExceptionWrapper.status_code_for_exception(payload[:exception][0])
21
-
22
- logger.fatal status: status, total_duration: total_duration, view_duration: view_duration, db_duration: db_duration, exception: payload[:exception]
18
+ logger.fatal view_duration: view_duration, db_duration: db_duration, exception: payload[:exception]
23
19
  else
24
- # Assume status 401 if action finishes without status code and no exception
25
- # https://github.com/pcg79/devise/commit/1e2dab3c0ce49efe2b5940c15f47388c69d6731b
26
- payload[:status] ||= 401
27
-
28
- logger.info status: payload[:status], total_duration: total_duration, view_duration: view_duration, db_duration: db_duration
20
+ logger.info view_duration: view_duration, db_duration: db_duration
29
21
  end
30
22
  end
31
23
  end
@@ -3,7 +3,7 @@ module Superlogger
3
3
  def render_template(event)
4
4
  payload = event.payload
5
5
 
6
- logger.debug view: payload[:identifier].split('/').last, duration: event.duration.round(1)
6
+ logger.debug {{ view: payload[:identifier].split('/').last, duration: event.duration.round(2) }}
7
7
  end
8
8
  alias :render_partial :render_template
9
9
  alias :render_collection :render_template
@@ -18,10 +18,12 @@ module Superlogger
18
18
  payload = event.payload
19
19
  return if IGNORE_PAYLOAD_NAMES.include?(payload[:name])
20
20
 
21
- sql = payload[:sql]
22
- params = payload[:binds].map { |_, value| value.to_s }
21
+ logger.debug do
22
+ sql = payload[:sql]
23
+ params = payload[:binds].map { |b| b.value.to_s }
23
24
 
24
- logger.debug sql: sql, params: params, duration: event.duration.round(2)
25
+ { sql: sql, params: params, duration: event.duration.round(2) }
26
+ end
25
27
  end
26
28
  end
27
29
  end
@@ -2,26 +2,25 @@ require 'request_store'
2
2
 
3
3
  module Superlogger
4
4
  class Logger < ActiveSupport::Logger
5
- def initialize(*args)
6
- super
7
- @formatter = SimpleFormatter.new
8
- end
9
-
10
5
  def format_message(severity, time, _progname, msg)
11
6
  return nil if msg.blank? # Silence nil and empty msg
12
7
  return nil if is_rails_rack_logger_msg?(msg) # Silence rack logger msg
13
8
 
14
- timestamp = time.strftime('%Y-%m-%d %H:%M:%S.%L')
15
- session_id = Superlogger.session_id[0..11]
16
- request_id = Superlogger.request_id[0..11]
17
- severity = severity.to_s.upcase[0]
18
- caller_location = get_caller_location
19
- args = format_args(msg)
9
+ msg = {msg: msg} unless msg.is_a?(Hash)
10
+
11
+ h = {}
12
+ h[:level] = severity.downcase
13
+ h[:ts] = time.to_f
14
+ h[:caller] = get_caller_location
15
+ h[:session_id] = Superlogger.session_id[0..11] unless Superlogger.session_id.nil?
16
+ h[:request_id] = Superlogger.request_id unless Superlogger.request_id.nil?
17
+ h.merge!(msg)
20
18
 
21
- "#{timestamp} | #{session_id} | #{request_id} | #{severity} | #{caller_location} | #{args}\n"
19
+ h.to_json + "\n"
22
20
  end
23
21
 
24
22
  def is_rails_rack_logger_msg?(msg)
23
+ return false unless msg.is_a?(String)
25
24
  msg =~ /Started (GET|POST|PUT|PATCH|DELETE)/
26
25
  end
27
26
 
@@ -30,25 +29,12 @@ module Superlogger
30
29
  location = caller_locations(index, 1).first
31
30
 
32
31
  # Extract filename without file extension from location.path
33
- # eg. superlogger/lib/superlogger/logger.rb
34
- file = location.path.split('/').last.split('.').first
32
+ # eg. superlogger/lib/superlogger/logger.rb => superlogger/logger
33
+ file = location.path.split('/').last(2).join('/').split('.').first
35
34
 
36
35
  "#{file}:#{location.lineno}"
37
36
  end
38
37
 
39
- def format_args(args)
40
- output = if args.is_a?(Hash)
41
- # Format args in key=value pair, separated by pipes
42
- args.map do |key, value|
43
- "#{key}=#{value}"
44
- end.join(' | ')
45
- else
46
- args.to_s
47
- end
48
-
49
- output.gsub("\n", '\\n') # Escape newlines
50
- end
51
-
52
38
  # To silence double logging when running `rails server` in development mode
53
39
  # See: https://github.com/rails/rails/commit/3d10d9d6c3b831fe9632c43a0ffec46104f912a7
54
40
  if Rails.env.development?
@@ -6,7 +6,7 @@ module Superlogger
6
6
 
7
7
  def call(env)
8
8
  request = ActionDispatch::Request.new(env)
9
-
9
+
10
10
  if request.path.start_with?('/assets/') == false
11
11
  process_request(request) { @app.call(env) }
12
12
  else
@@ -18,27 +18,26 @@ module Superlogger
18
18
  setup_logging(request)
19
19
 
20
20
  # Start of request
21
- Rails.logger.info method: request.method, path: request.fullpath, ip: request.ip
21
+ Rails.logger.info method: request.method, path: request.fullpath
22
22
 
23
23
  t1 = Time.now
24
- result = yield
24
+ status, _headers, _response = yield
25
25
  ensure
26
26
  t2 = Time.now
27
27
 
28
28
  # End of request
29
29
  duration = ((t2 - t1) * 1000).to_f.round(2)
30
- Rails.logger.info method: request.method, path: request.fullpath, total_duration: duration
30
+ Rails.logger.info method: request.method, path: request.fullpath, response_time: duration, status: status
31
31
 
32
- result
32
+ [status, _headers, _response]
33
33
  end
34
34
 
35
35
  def setup_logging(request)
36
36
  if request.env['rack.session']
37
- # Session is lazy loaded. Force session to load if it is not already loaded.
38
- request.env['rack.session'].send(:load!) unless request.env['rack.session'].id
39
-
40
37
  # Store session id before any actual logging is done
41
- Superlogger.session_id = request.env['rack.session'].id
38
+ if request.env['rack.session'].id
39
+ Superlogger.session_id = request.env['rack.session'].id.to_s
40
+ end
42
41
  end
43
42
 
44
43
  Superlogger.request_id = request.uuid.try(:gsub, '-', '')
@@ -1,3 +1,3 @@
1
1
  module Superlogger
2
- VERSION = '0.2.1'
2
+ VERSION = '1.0.1'
3
3
  end
data/lib/superlogger.rb CHANGED
@@ -2,9 +2,13 @@ require 'superlogger/version'
2
2
  require 'superlogger/logger'
3
3
 
4
4
  module Superlogger
5
+ @@enabled = false
6
+
5
7
  module_function
6
8
 
7
9
  def setup(app)
10
+ return unless (Rails.env.production? || enabled)
11
+
8
12
  insert_superlogger_middleware(app)
9
13
  detach_existing_log_subscribers
10
14
  attach_superlogger_log_subscribers
@@ -24,7 +28,7 @@ module Superlogger
24
28
  require 'action_view/log_subscriber'
25
29
 
26
30
  # remove log subscribers
27
- patterns = %w(sql.active_record
31
+ remove_patterns = %w(sql.active_record
28
32
  start_processing.action_controller
29
33
  process_action.action_controller
30
34
  render_template.action_view
@@ -32,8 +36,11 @@ module Superlogger
32
36
  render_collection.action_view)
33
37
 
34
38
  ActiveSupport::LogSubscriber.log_subscribers.each do |subscriber|
35
- subscriber.patterns.each do |pattern|
36
- ActiveSupport::Notifications.unsubscribe pattern if patterns.include?(pattern)
39
+ patterns = subscriber.patterns
40
+ patterns = patterns.is_a?(Hash) ? patterns.keys : patterns
41
+
42
+ patterns.each do |pattern|
43
+ ActiveSupport::Notifications.unsubscribe pattern if remove_patterns.include?(pattern)
37
44
  end
38
45
  end
39
46
  end
@@ -49,7 +56,7 @@ module Superlogger
49
56
  end
50
57
 
51
58
  def session_id
52
- RequestStore.store[:superlogger_session_id] || "NS-#{Thread.current.object_id}"
59
+ RequestStore.store[:superlogger_session_id]
53
60
  end
54
61
 
55
62
  def request_id=(request_id)
@@ -57,7 +64,15 @@ module Superlogger
57
64
  end
58
65
 
59
66
  def request_id
60
- RequestStore.store[:superlogger_request_id] || "NR-#{Thread.current.object_id}"
67
+ RequestStore.store[:superlogger_request_id]
68
+ end
69
+
70
+ def enabled=(enabled)
71
+ @@enabled=enabled
72
+ end
73
+
74
+ def enabled
75
+ @@enabled
61
76
  end
62
77
  end
63
78
 
@@ -0,0 +1,3 @@
1
+ //= link_tree ../images
2
+ //= link_directory ../javascripts .js
3
+ //= link_directory ../stylesheets .css
@@ -19,8 +19,9 @@ module Dummy
19
19
  # config.i18n.default_locale = :de
20
20
 
21
21
  # Do not swallow errors in after_commit/after_rollback callbacks.
22
- config.active_record.raise_in_transactional_callbacks = true
23
-
22
+ # config.active_record.raise_in_transactional_callbacks = true
23
+
24
+ Superlogger.enabled = true
24
25
  config.logger = Superlogger::Logger.new(STDOUT)
25
26
  end
26
27
  end
@@ -25,7 +25,7 @@ class SuperloggerTest < ActiveSupport::TestCase
25
25
 
26
26
  def output
27
27
  @parsed_output ||= @output.string.split("\n").map do |line|
28
- line.split(' | ')
28
+ JSON.parse(line)
29
29
  end
30
30
  end
31
31
 
@@ -37,128 +37,100 @@ class SuperloggerTest < ActiveSupport::TestCase
37
37
  request('home/index')
38
38
 
39
39
  fields = output.first
40
- assert fields[0].length == 23
41
- assert fields[1].length == 12
42
- assert fields[2].length == 12
43
- assert fields[3].length == 1
44
- assert_match(/\w:\d+/, fields[4])
40
+ assert fields.key?("level")
41
+ assert fields.key?("ts")
42
+ assert fields.key?("caller")
43
+ assert fields.key?("session_id")
44
+ assert fields.key?("request_id")
45
45
  end
46
46
 
47
47
  test 'timestamp' do
48
48
  request('home/index')
49
- assert DateTime.parse(output[0][0]).to_date == Date.today
49
+ assert_equal Time.at(output[0]["ts"]).to_date, Date.today
50
50
  end
51
51
 
52
52
  test 'with session_id' do
53
53
  env = request('home/index')
54
- assert_match env['rack.session'].id[0..11], output[0][1]
54
+ assert_match env['rack.session'].id.to_s[0..11], output[0]["session_id"]
55
55
  end
56
56
 
57
57
  test 'without session_id' do
58
58
  Rails.logger.debug var: 'test'
59
- assert_match(/^NS-[[:alnum:]]+$/, output[0][1])
59
+ assert_equal output[0].key?("session_id"), false
60
60
  end
61
61
 
62
62
  test 'with request_id' do
63
63
  request('home/index')
64
- assert_no_match(/^NR-[[:alnum:]]+$/, output[0][2])
64
+ assert_no_match(/^NR-[[:alnum:]]+$/, output[0]["request_id"])
65
65
  end
66
66
 
67
67
  test 'without request_id' do
68
68
  Rails.logger.debug var: 'test'
69
- assert_match(/^NR-[[:alnum:]]+$/, output[0][2])
70
- end
71
-
72
- test 'log levels' do
73
- Rails.logger.debug var: 'test'
74
- Rails.logger.info var: 'test'
75
- Rails.logger.warn var: 'test'
76
- Rails.logger.error var: 'test'
77
- Rails.logger.fatal var: 'test'
78
-
79
- assert output[0][3] == 'D'
80
- assert output[1][3] == 'I'
81
- assert output[2][3] == 'W'
82
- assert output[3][3] == 'E'
83
- assert output[4][3] == 'F'
69
+ assert_equal output[0].key?("request_id"), false
84
70
  end
85
71
 
86
72
  test 'caller location' do
87
73
  Rails.logger.debug var: 'test'
88
- assert output[0][4] == "superlogger_test:#{__LINE__ - 1}"
74
+ assert_equal output[0]["caller"], "test/superlogger_test:#{__LINE__ - 1}"
89
75
  end
90
76
 
91
77
  test 'silence_rails_rack_logger' do
92
78
  request('home/index')
93
- assert_no_match 'Started GET', output[0][5]
79
+ assert_no_match 'Started GET', output[0]["msg"]
94
80
  end
95
81
 
96
82
  test 'middleware start' do
97
83
  request('home/index', 'REMOTE_ADDR' => '::1')
98
84
 
99
85
  fields = output[0]
100
- assert_match 'method=GET', fields[5]
101
- assert_match 'path=/home/index', fields[6]
102
- assert_match 'ip=::1', fields[7]
86
+ assert_match 'GET', fields["method"]
87
+ assert_match '/home/index', fields["path"]
103
88
  end
104
89
 
105
90
  test 'middleware end' do
106
91
  request('home/index', 'REMOTE_ADDR' => '::1')
107
92
 
108
93
  fields = output.last
109
- assert_match 'method=GET', fields[5]
110
- assert_match 'path=/home/index', fields[6]
111
- assert_match(/^total_duration=\d+.\d+$/, fields[7])
112
- assert_operator fields[7].split('=').last.to_f, :>, 0
94
+ assert_match 'GET', fields["method"]
95
+ assert_match '/home/index', fields["path"]
96
+ assert_operator fields["response_time"], :>, 0
113
97
  end
114
98
 
115
99
  test 'action_controller_log_subscriber.start_processing' do
116
100
  request('home/index?a=1')
117
101
 
118
102
  fields = output[1]
119
- assert_match 'controller=HomeController', fields[5]
120
- assert_match 'action=index', fields[6]
121
- assert_match 'params={"a"=>"1"}', fields[7]
103
+ assert_match 'HomeController', fields["controller"]
104
+ assert_match 'index', fields["action"]
105
+ assert_equal Hash.new.tap {|h| h["a"] ="1"}, fields["params"]
122
106
  end
123
107
 
124
108
  test 'action_controller_log_subscriber.process_action' do
125
109
  request('home/index')
126
110
 
127
111
  fields = output[5]
128
- assert_match 'status=200', fields[5]
129
- assert_match(/^total_duration=\d+.\d+$/, fields[6])
130
- assert_operator fields[6].split('=').last.to_f, :>, 0
131
- assert_match(/^view_duration=\d+.\d+$/, fields[7])
132
- assert_operator fields[7].split('=').last.to_f, :>, 0
133
- assert_match(/^db_duration=\d+.\d+$/, fields[8])
134
- assert_operator fields[8].split('=').last.to_f, :>, 0
112
+ assert_operator fields["view_duration"], :>, 0
113
+ assert_operator fields["db_duration"], :>, 0
135
114
  end
136
115
 
137
116
  test 'action_view_log_subscriber.render_template.render_partial.render_collection' do
138
117
  request('home/index')
139
118
 
140
119
  fields = output[3]
141
- assert_match 'view=_partial.html.erb', fields[5]
142
- assert_match 'duration=', fields[6]
120
+ assert_match 'partial.html.erb', fields["view"]
121
+ assert fields.key?("duration")
143
122
 
144
123
  fields = output[4]
145
- assert_match 'view=index.html.erb', fields[5]
146
- assert_match 'duration=', fields[6]
124
+ assert_match 'index.html.erb', fields["view"]
125
+ assert fields.key?("duration")
147
126
  end
148
127
 
149
128
  test 'active_record_log_subscriber.sql' do
150
129
  request('home/index')
151
130
 
152
131
  fields = output[2]
153
- assert_match 'sql=SELECT', fields[5]
154
- assert_match 'params=[', fields[6]
155
- assert_match(/^duration=\d+.\d+$/, fields[7])
156
- assert_operator fields[7].split('=').last.to_f, :>, 0
157
- end
158
-
159
- test 'escape new lines' do
160
- Rails.logger.debug var: 'first\nsecond'
161
-
162
- assert_match 'first\\nsecond', output[0].last
132
+ assert_match 'SELECT', fields["sql"]
133
+ assert_equal ["123", "456", "1"], fields["params"]
134
+ assert_operator fields["duration"], :>, 0
163
135
  end
164
136
  end