sessionflusher.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import { dropUndefinedKeys } from '@sentry/utils';
  2. import { getCurrentScope } from './exports.js';
  3. /**
  4. * @inheritdoc
  5. */
  6. class SessionFlusher {
  7. constructor(client, attrs) {
  8. this._client = client;
  9. this.flushTimeout = 60;
  10. this._pendingAggregates = {};
  11. this._isEnabled = true;
  12. // Call to setInterval, so that flush is called every 60 seconds
  13. this._intervalId = setInterval(() => this.flush(), this.flushTimeout * 1000);
  14. this._sessionAttrs = attrs;
  15. }
  16. /** Checks if `pendingAggregates` has entries, and if it does flushes them by calling `sendSession` */
  17. flush() {
  18. const sessionAggregates = this.getSessionAggregates();
  19. if (sessionAggregates.aggregates.length === 0) {
  20. return;
  21. }
  22. this._pendingAggregates = {};
  23. this._client.sendSession(sessionAggregates);
  24. }
  25. /** Massages the entries in `pendingAggregates` and returns aggregated sessions */
  26. getSessionAggregates() {
  27. const aggregates = Object.keys(this._pendingAggregates).map((key) => {
  28. return this._pendingAggregates[parseInt(key)];
  29. });
  30. const sessionAggregates = {
  31. attrs: this._sessionAttrs,
  32. aggregates,
  33. };
  34. return dropUndefinedKeys(sessionAggregates);
  35. }
  36. /** JSDoc */
  37. close() {
  38. clearInterval(this._intervalId);
  39. this._isEnabled = false;
  40. this.flush();
  41. }
  42. /**
  43. * Wrapper function for _incrementSessionStatusCount that checks if the instance of SessionFlusher is enabled then
  44. * fetches the session status of the request from `Scope.getRequestSession().status` on the scope and passes them to
  45. * `_incrementSessionStatusCount` along with the start date
  46. */
  47. incrementSessionStatusCount() {
  48. if (!this._isEnabled) {
  49. return;
  50. }
  51. const scope = getCurrentScope();
  52. const requestSession = scope.getRequestSession();
  53. if (requestSession && requestSession.status) {
  54. this._incrementSessionStatusCount(requestSession.status, new Date());
  55. // This is not entirely necessarily but is added as a safe guard to indicate the bounds of a request and so in
  56. // case captureRequestSession is called more than once to prevent double count
  57. scope.setRequestSession(undefined);
  58. /* eslint-enable @typescript-eslint/no-unsafe-member-access */
  59. }
  60. }
  61. /**
  62. * Increments status bucket in pendingAggregates buffer (internal state) corresponding to status of
  63. * the session received
  64. */
  65. _incrementSessionStatusCount(status, date) {
  66. // Truncate minutes and seconds on Session Started attribute to have one minute bucket keys
  67. const sessionStartedTrunc = new Date(date).setSeconds(0, 0);
  68. this._pendingAggregates[sessionStartedTrunc] = this._pendingAggregates[sessionStartedTrunc] || {};
  69. // corresponds to aggregated sessions in one specific minute bucket
  70. // for example, {"started":"2021-03-16T08:00:00.000Z","exited":4, "errored": 1}
  71. const aggregationCounts = this._pendingAggregates[sessionStartedTrunc];
  72. if (!aggregationCounts.started) {
  73. aggregationCounts.started = new Date(sessionStartedTrunc).toISOString();
  74. }
  75. switch (status) {
  76. case 'errored':
  77. aggregationCounts.errored = (aggregationCounts.errored || 0) + 1;
  78. return aggregationCounts.errored;
  79. case 'ok':
  80. aggregationCounts.exited = (aggregationCounts.exited || 0) + 1;
  81. return aggregationCounts.exited;
  82. default:
  83. aggregationCounts.crashed = (aggregationCounts.crashed || 0) + 1;
  84. return aggregationCounts.crashed;
  85. }
  86. }
  87. }
  88. export { SessionFlusher };
  89. //# sourceMappingURL=sessionflusher.js.map