You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

JitsiMeetLogStorage.ts 4.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. /* eslint-disable lines-around-comment */
  2. // @ts-ignore
  3. import RTCStats from '../../rtcstats/RTCStats';
  4. // @ts-ignore
  5. import { canSendRtcstatsData } from '../../rtcstats/functions';
  6. // @ts-ignore
  7. import { getCurrentConference } from '../conference';
  8. /**
  9. * Implements log storage interface from the @jitsi/logger lib. Captured
  10. * logs are sent to CallStats.
  11. */
  12. export default class JitsiMeetLogStorage {
  13. counter: number;
  14. getState: Function;
  15. /**
  16. * Creates new <tt>JitsiMeetLogStorage</tt>.
  17. *
  18. * @param {Function} getState - The Redux store's {@code getState} method.
  19. */
  20. constructor(getState: Function) {
  21. /**
  22. * Counts each log entry, increases on every batch log entry stored.
  23. *
  24. * @type {number}
  25. */
  26. this.counter = 1;
  27. /**
  28. * The Redux store's {@code getState} method.
  29. *
  30. * @type {Function}
  31. */
  32. this.getState = getState;
  33. }
  34. /**
  35. * The JitsiMeetLogStorage is ready when the CallStats are started and
  36. * before refactoring the code it was after the conference has been joined.
  37. * A conference is considered joined when the 'conference' field is defined
  38. * in the base/conference state.
  39. *
  40. * @returns {boolean} <tt>true</tt> when this storage is ready or
  41. * <tt>false</tt> otherwise.
  42. */
  43. isReady() {
  44. const { conference } = this.getState()['features/base/conference'];
  45. return Boolean(conference);
  46. }
  47. /**
  48. * Checks whether callstats logs storage is enabled.
  49. *
  50. * @returns {boolean} <tt>true</tt> when this storage can store logs to
  51. * callstats, <tt>false</tt> otherwise.
  52. */
  53. canStoreLogsCallstats() {
  54. const { callstatsStoreLogs } = this.getState()['features/base/config'];
  55. // The behavior prior to adding this configuration parameter, is to send logs to callstats (if callstats is
  56. // enabled). So, in order to maintain backwards compatibility I set the default of this option to be true, i.e.
  57. // if the config.callstatsStoreLogs is not set, the JS console logs will be sent to callstats (if callstats is
  58. // enabled)
  59. return callstatsStoreLogs || callstatsStoreLogs === undefined;
  60. }
  61. /**
  62. * Checks whether rtcstats logs storage is enabled.
  63. *
  64. * @returns {boolean} <tt>true</tt> when this storage can store logs to
  65. * rtcstats, <tt>false</tt> otherwise.
  66. */
  67. canStoreLogsRtcstats() {
  68. const config = this.getState()['features/base/config'];
  69. // Saving the logs in RTCStats is a new feature and so there is no prior behavior that needs to be maintained.
  70. // That said, this is still experimental and needs to be rolled out gradually so we want this to be off by
  71. // default.
  72. return config?.analytics?.rtcstatsStoreLogs && canSendRtcstatsData(this.getState());
  73. }
  74. /**
  75. * Called by the <tt>LogCollector</tt> to store a series of log lines into
  76. * batch.
  77. *
  78. * @param {Array<string|Object>} logEntries - An array containing strings
  79. * representing log lines or aggregated lines objects.
  80. * @returns {void}
  81. */
  82. storeLogs(logEntries: Array<string | any>) {
  83. if (this.canStoreLogsCallstats()) {
  84. this.storeLogsCallstats(logEntries);
  85. }
  86. if (this.canStoreLogsRtcstats()) {
  87. RTCStats.sendLogs(logEntries);
  88. }
  89. }
  90. /**
  91. * Store the console logs in callstats (if callstats is enabled).
  92. *
  93. * @param {Array<string|any>} logEntries - The log entries to send to the rtcstats server.
  94. * @returns {void}
  95. */
  96. storeLogsCallstats(logEntries: Array<string | any>) {
  97. const conference = getCurrentConference(this.getState());
  98. if (!conference || !conference.isCallstatsEnabled()) {
  99. // Discard the logs if CallStats is not enabled.
  100. return;
  101. }
  102. let logMessage = `{"log${this.counter}":"\n`;
  103. for (let i = 0, len = logEntries.length; i < len; i++) {
  104. const logEntry = logEntries[i];
  105. if (logEntry.timestamp) {
  106. logMessage += `${logEntry.timestamp} `;
  107. }
  108. if (logEntry.count > 1) {
  109. logMessage += `(${logEntry.count}) `;
  110. }
  111. logMessage += `${logEntry.text}\n`;
  112. }
  113. logMessage += '"}';
  114. this.counter += 1;
  115. // Try catch was used, because there are many variables
  116. // on the way that could be uninitialized if the storeLogs
  117. // attempt would be made very early (which is unlikely)
  118. try {
  119. conference.sendApplicationLog(logMessage);
  120. } catch (error) {
  121. // NOTE console is intentional here
  122. console.error(
  123. `Failed to store the logs, msg length: ${logMessage.length}`
  124. + `error: ${JSON.stringify(error)}`);
  125. }
  126. }
  127. }