log.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. /* This is free software, licensed under the Apache License, Version 2.0
  2. *
  3. * Copyright (C) 2024 Hilman Maulana <hilman0.0maulana@gmail.com>
  4. */
  5. 'use strict';
  6. 'require fs';
  7. 'require ui';
  8. 'require view';
  9. 'require poll';
  10. function formatLogEntry(logObj) {
  11. var formattedTime = new Date(logObj.time).toISOString().replace('T', ' ').split('.')[0];
  12. var tunnelIDMessage = logObj.tunnelID ? ', ID: ' + logObj.tunnelID : '';
  13. var errorMessage = logObj.error ? ', Error: ' + logObj.error : '';
  14. var ipMessage = logObj.ip ? ', IP: ' + logObj.ip : '';
  15. var configMessage = logObj.config ? ', Config: ' + JSON.stringify(logObj.config) : '';
  16. var connectionMessage = logObj.connection ? ', Connection: ' + JSON.stringify(logObj.connection) : '';
  17. var locationMessage = logObj.location ? ', Location: ' + logObj.location : '';
  18. var protocolMessage = logObj.protocol ? ', Protocol: ' + logObj.protocol : '';
  19. return '[' + formattedTime + '] [' + logObj.level + '] : ' + logObj.message + ipMessage + tunnelIDMessage + errorMessage + configMessage + connectionMessage + locationMessage + protocolMessage;
  20. }
  21. return view.extend({
  22. handleSaveApply: null,
  23. handleSave: null,
  24. handleReset: null,
  25. load: function() {
  26. poll.add(function () {
  27. return fs.read('/var/log/cloudflared.log').then(function(res) {
  28. if (!res || res.trim() === '') {
  29. ui.addNotification(null, E('p', {}, _('Unable to read the interface info from /var/log/cloudflared.log.')));
  30. return '';
  31. }
  32. var logs = res.trim().split('\n').map(function(entry) {
  33. try {
  34. var logObj = JSON.parse(entry);
  35. return logObj.time && logObj.message && logObj.level
  36. ? formatLogEntry(logObj)
  37. : '';
  38. } catch (error) {
  39. console.error('Error parsing log entry:', error);
  40. return '';
  41. }
  42. });
  43. logs = logs.filter(function(entry) {
  44. return entry.trim() !== '';
  45. });
  46. var info = logs.join('\n');
  47. var view = document.getElementById('syslog');
  48. var filterLevel = document.getElementById('filter-level').value;
  49. var logDirection = document.getElementById('log-direction').value;
  50. if (view) {
  51. var filteredLogs;
  52. if (filterLevel !== 'all') {
  53. filteredLogs = logs.filter(function(entry) {
  54. var logLevel = entry.match(/\[.*\] \[(.*)\]/)[1].toLowerCase();
  55. return logLevel.includes(filterLevel.toLowerCase());
  56. });
  57. } else {
  58. filteredLogs = logs;
  59. }
  60. if (logDirection === 'up') {
  61. filteredLogs = filteredLogs.reverse();
  62. }
  63. info = filteredLogs.join('\n');
  64. view.innerHTML = info;
  65. }
  66. return info;
  67. });
  68. });
  69. return Promise.resolve('');
  70. },
  71. render: function(info) {
  72. return E([], [
  73. E('h2', { 'class': 'section-title' }, _('Log')),
  74. E('div', { 'id': 'logs' }, [
  75. E('label', { 'for': 'filter-level', 'style': 'margin-right: 8px;' }, _('Filter Level:')),
  76. E('select', { 'id': 'filter-level', 'style': 'margin-right: 8px;' }, [
  77. E('option', { 'value': 'all', 'selected': 'selected' }, _('All')),
  78. E('option', { 'value': 'info' }, _('Info')),
  79. E('option', { 'value': 'warn' }, _('Warn')),
  80. E('option', { 'value': 'error' }, _('Error')),
  81. ]),
  82. E('label', { 'for': 'log-direction', 'style': 'margin-right: 8px;' }, _('Log Direction:')),
  83. E('select', { 'id': 'log-direction', 'style': 'margin-right: 8px;' }, [
  84. E('option', { 'value': 'down', 'selected': 'selected' }, _('Down')),
  85. E('option', { 'value': 'up' }, _('Up')),
  86. ]),
  87. E('button', {
  88. 'id': 'download-log',
  89. 'class': 'cbi-button cbi-button-save',
  90. 'click': L.bind(this.handleDownloadLog, this),
  91. 'style': 'margin-bottom: 8px;'
  92. }, _('Download Log')),
  93. E('textarea', {
  94. 'id': 'syslog',
  95. 'class': 'cbi-input-textarea',
  96. 'style': 'height: 500px; overflow-y: scroll;',
  97. 'readonly': 'readonly',
  98. 'wrap': 'off',
  99. 'rows': 1
  100. }, [ info ])
  101. ])
  102. ]);
  103. },
  104. handleDownloadLog: function() {
  105. var logs = document.getElementById('syslog').value;
  106. var blob = new Blob([logs], { type: 'text/plain' });
  107. var link = document.createElement('a');
  108. link.href = window.URL.createObjectURL(blob);
  109. link.download = 'cloudflared.log';
  110. link.click();
  111. }
  112. });