logger.html.twig 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. {% extends '@WebProfiler/Profiler/layout.html.twig' %}
  2. {% import _self as helper %}
  3. {% block toolbar %}
  4. {% if collector.counterrors or collector.countdeprecations or collector.countwarnings %}
  5. {% set icon %}
  6. {% set status_color = collector.counterrors ? 'red' : collector.countwarnings ? 'yellow' : 'none' %}
  7. {{ include('@WebProfiler/Icon/logger.svg') }}
  8. <span class="sf-toolbar-value">{{ collector.counterrors ?: (collector.countdeprecations + collector.countwarnings) }}</span>
  9. {% endset %}
  10. {% set text %}
  11. <div class="sf-toolbar-info-piece">
  12. <b>Errors</b>
  13. <span class="sf-toolbar-status sf-toolbar-status-{{ collector.counterrors ? 'red' }}">{{ collector.counterrors|default(0) }}</span>
  14. </div>
  15. <div class="sf-toolbar-info-piece">
  16. <b>Warnings</b>
  17. <span class="sf-toolbar-status sf-toolbar-status-{{ collector.countwarnings ? 'yellow' }}">{{ collector.countwarnings|default(0) }}</span>
  18. </div>
  19. <div class="sf-toolbar-info-piece">
  20. <b>Deprecations</b>
  21. <span class="sf-toolbar-status sf-toolbar-status-{{ collector.countdeprecations ? 'none' }}">{{ collector.countdeprecations|default(0) }}</span>
  22. </div>
  23. {% endset %}
  24. {{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { link: profiler_url, status: status_color }) }}
  25. {% endif %}
  26. {% endblock %}
  27. {% block menu %}
  28. <span class="label label-status-{{ collector.counterrors ? 'error' : collector.countwarnings ? 'warning' : 'none' }} {{ collector.logs is empty ? 'disabled' }}">
  29. <span class="icon">{{ include('@WebProfiler/Icon/logger.svg') }}</span>
  30. <strong>Logs</strong>
  31. {% if collector.counterrors or collector.countdeprecations or collector.countwarnings %}
  32. <span class="count">
  33. <span>{{ collector.counterrors ?: (collector.countdeprecations + collector.countwarnings) }}</span>
  34. </span>
  35. {% endif %}
  36. </span>
  37. {% endblock %}
  38. {% block panel %}
  39. <h2>Log Messages</h2>
  40. {% if collector.logs is empty %}
  41. <div class="empty">
  42. <p>No log messages available.</p>
  43. </div>
  44. {% else %}
  45. {# sort collected logs in groups #}
  46. {% set deprecation_logs, debug_logs, info_and_error_logs, silenced_logs = [], [], [], [] %}
  47. {% set has_error_logs = false %}
  48. {% for log in collector.logs %}
  49. {% if log.scream is defined and not log.scream %}
  50. {% set deprecation_logs = deprecation_logs|merge([log]) %}
  51. {% elseif log.scream is defined and log.scream %}
  52. {% set silenced_logs = silenced_logs|merge([log]) %}
  53. {% elseif log.priorityName == 'DEBUG' %}
  54. {% set debug_logs = debug_logs|merge([log]) %}
  55. {% else %}
  56. {% set info_and_error_logs = info_and_error_logs|merge([log]) %}
  57. {% if log.priorityName != 'INFO' %}
  58. {% set has_error_logs = true %}
  59. {% endif %}
  60. {% endif %}
  61. {% endfor %}
  62. <div class="sf-tabs">
  63. <div class="tab {{ has_error_logs ? 'active' }}">
  64. <h3 class="tab-title">Info. &amp; Errors <span class="badge status-{{ collector.counterrors ? 'error' : collector.countwarnings ? 'warning' }}">{{ collector.counterrors ?: info_and_error_logs|length }}</span></h3>
  65. <p class="text-muted">Informational and error log messages generated during the execution of the application.</p>
  66. <div class="tab-content">
  67. {% if info_and_error_logs is empty %}
  68. <div class="empty">
  69. <p>There are no log messages of this level.</p>
  70. </div>
  71. {% else %}
  72. {{ helper.render_table(info_and_error_logs, 'info', true) }}
  73. {% endif %}
  74. </div>
  75. </div>
  76. <div class="tab {{ not has_error_logs and collector.countdeprecations > 0 ? 'active' }}">
  77. {# 'deprecation_logs|length' is not used because deprecations are
  78. now grouped and the group count doesn't match the message count #}
  79. <h3 class="tab-title">Deprecations <span class="badge status-{{ collector.countdeprecations ? 'none' }}">{{ collector.countdeprecations|default(0) }}</span></h3>
  80. <p class="text-muted">Log messages generated by using features marked as deprecated.</p>
  81. <div class="tab-content">
  82. {% if deprecation_logs is empty %}
  83. <div class="empty">
  84. <p>There are no log messages about deprecated features.</p>
  85. </div>
  86. {% else %}
  87. {{ helper.render_table(deprecation_logs, 'deprecation', false, true) }}
  88. {% endif %}
  89. </div>
  90. </div>
  91. <div class="tab">
  92. <h3 class="tab-title">Debug <span class="badge">{{ debug_logs|length }}</span></h3>
  93. <p class="text-muted">Unimportant log messages generated during the execution of the application.</p>
  94. <div class="tab-content">
  95. {% if debug_logs is empty %}
  96. <div class="empty">
  97. <p>There are no log messages of this level.</p>
  98. </div>
  99. {% else %}
  100. {{ helper.render_table(debug_logs, 'debug') }}
  101. {% endif %}
  102. </div>
  103. </div>
  104. <div class="tab">
  105. <h3 class="tab-title">PHP Notices <span class="badge">{{ collector.countscreams|default(0) }}</span></h3>
  106. <p class="text-muted">Log messages generated by PHP notices silenced with the @ operator.</p>
  107. <div class="tab-content">
  108. {% if silenced_logs is empty %}
  109. <div class="empty">
  110. <p>There are no log messages of this level.</p>
  111. </div>
  112. {% else %}
  113. {{ helper.render_table(silenced_logs, 'silenced') }}
  114. {% endif %}
  115. </div>
  116. </div>
  117. {% set compilerLogTotal = 0 %}
  118. {% for logs in collector.compilerLogs %}
  119. {% set compilerLogTotal = compilerLogTotal + logs|length %}
  120. {% endfor %}
  121. <div class="tab">
  122. <h3 class="tab-title">Container <span class="badge">{{ compilerLogTotal }}</span></h3>
  123. <p class="text-muted">Log messages generated during the compilation of the service container.</p>
  124. <div class="tab-content">
  125. {% if collector.compilerLogs is empty %}
  126. <div class="empty">
  127. <p>There are no compiler log messages.</p>
  128. </div>
  129. {% else %}
  130. <table class="logs">
  131. <thead>
  132. <tr>
  133. <th class="full-width">Class</th>
  134. <th>Messages</th>
  135. </tr>
  136. </thead>
  137. <tbody>
  138. {% for class, logs in collector.compilerLogs %}
  139. <tr class="">
  140. <td class="font-normal">
  141. {% set context_id = 'context-compiler-' ~ loop.index %}
  142. <a class="btn btn-link sf-toggle" data-toggle-selector="#{{ context_id }}" data-toggle-alt-content="{{ class }}">{{ class }}</a>
  143. <div id="{{ context_id }}" class="context sf-toggle-content sf-toggle-hidden">
  144. <ul>
  145. {% for log in logs %}
  146. <li>{{ profiler_dump_log(log.message) }}</li>
  147. {% endfor %}
  148. </ul>
  149. </div>
  150. </td>
  151. <td class="font-normal text-right">{{ logs|length }}</td>
  152. </tr>
  153. {% endfor %}
  154. </tbody>
  155. </table>
  156. {% endif %}
  157. </div>
  158. </div>
  159. </div>
  160. <script>Sfjs.createFilters();</script>
  161. {% endif %}
  162. {% endblock %}
  163. {% macro render_table(logs, category = '', show_level = false, is_deprecation = false) %}
  164. {% import _self as helper %}
  165. {% set channel_is_defined = (logs|first).channel is defined %}
  166. {% set filter = show_level or channel_is_defined %}
  167. <table class="logs"{% if show_level %} data-filter-level="Emergency,Alert,Critical,Error,Warning,Notice,Info"{% endif %}{% if filter %} data-filters{% endif %}>
  168. <thead>
  169. <tr>
  170. {% if show_level %}<th data-filter="level">Level</th>{% else %}<th>Time</th>{% endif %}
  171. {% if channel_is_defined %}<th data-filter="channel">Channel</th>{% endif %}
  172. <th class="full-width">Message</th>
  173. </tr>
  174. </thead>
  175. <tbody>
  176. {% for log in logs %}
  177. {% set css_class = is_deprecation ? ''
  178. : log.priorityName in ['CRITICAL', 'ERROR', 'ALERT', 'EMERGENCY'] ? 'status-error'
  179. : log.priorityName == 'WARNING' ? 'status-warning'
  180. %}
  181. <tr class="{{ css_class }}"{% if show_level %} data-filter-level="{{ log.priorityName|lower }}"{% endif %}{% if channel_is_defined %} data-filter-channel="{{ log.channel is not null ? log.channel : '' }}"{% endif %}>
  182. <td class="font-normal text-small" nowrap>
  183. {% if show_level %}
  184. <span class="colored text-bold">{{ log.priorityName }}</span>
  185. {% endif %}
  186. <time class="text-muted newline" title="{{ log.timestamp|date('r') }}" datetime="{{ log.timestamp|date('c') }}">{{ log.timestamp|date('H:i:s') }}</time>
  187. </td>
  188. {% if channel_is_defined %}
  189. <td class="font-normal text-small text-bold" nowrap>
  190. {% if log.channel is null %}<em>n/a</em>{% else %}{{ log.channel }}{% endif %}
  191. {% if log.errorCount is defined and log.errorCount > 1 %}
  192. <span class="text-muted">({{ log.errorCount }} times)</span>
  193. {% endif %}
  194. </td>
  195. {% endif %}
  196. <td class="font-normal">{{ helper.render_log_message(category, loop.index, log) }}</td>
  197. </tr>
  198. {% endfor %}
  199. </tbody>
  200. </table>
  201. {% endmacro %}
  202. {% macro render_log_message(category, log_index, log) %}
  203. {% set has_context = log.context is defined and log.context is not empty %}
  204. {% set has_trace = log.context.exception.trace is defined %}
  205. {% if not has_context %}
  206. {{ profiler_dump_log(log.message) }}
  207. {% else %}
  208. {{ profiler_dump_log(log.message, log.context) }}
  209. <div class="text-small font-normal">
  210. {% set context_id = 'context-' ~ category ~ '-' ~ log_index %}
  211. <a class="btn btn-link text-small sf-toggle" data-toggle-selector="#{{ context_id }}" data-toggle-alt-content="Hide context">Show context</a>
  212. {% if has_trace %}
  213. &nbsp;&nbsp;
  214. {% set trace_id = 'trace-' ~ category ~ '-' ~ log_index %}
  215. <a class="btn btn-link text-small sf-toggle" data-toggle-selector="#{{ trace_id }}" data-toggle-alt-content="Hide trace">Show trace</a>
  216. {% endif %}
  217. </div>
  218. <div id="{{ context_id }}" class="context sf-toggle-content sf-toggle-hidden">
  219. {{ profiler_dump(log.context, maxDepth=1) }}
  220. </div>
  221. {% if has_trace %}
  222. <div id="{{ trace_id }}" class="context sf-toggle-content sf-toggle-hidden">
  223. {{ profiler_dump(log.context.exception.trace, maxDepth=1) }}
  224. </div>
  225. {% endif %}
  226. {% endif %}
  227. {% endmacro %}