private prepareEventsPayload()

in glean/src/core/metrics/events_database/index.ts [328:417]


  private prepareEventsPayload(pingName: string, pingData: RecordedEvent[]): JSONArray {
    // Sort events by execution counter and by timestamp.
    let sortedEvents = pingData.sort((a, b) => {
      const executionCounterA = Number(a.get().extra?.[GLEAN_EXECUTION_COUNTER_EXTRA_KEY]);
      const executionCounterB = Number(b.get().extra?.[GLEAN_EXECUTION_COUNTER_EXTRA_KEY]);
      // Sort by execution counter, in case they are different.
      if (executionCounterA !== executionCounterB) {
        return executionCounterA - executionCounterB;
      }

      // Sort by timestamp if events come from same execution.
      return a.get().timestamp - b.get().timestamp;
    });

    let lastRestartDate: Date;
    try {
      lastRestartDate = createDateObject(
        sortedEvents[0].get().extra?.[GLEAN_REFERENCE_TIME_EXTRA_KEY]
      );
      // Drop the first `restarted` event.
      sortedEvents.shift();
    } catch {
      // In the unlikely case that the first event was not a `glean.restarted` event,
      // let's rely on the start time of the current session.
      lastRestartDate = Context.startTime;
    }

    const firstEventOffset = sortedEvents[0]?.get().timestamp || 0;
    let restartedOffset = 0;
    for (const [index, event] of sortedEvents.entries()) {
      try {
        const nextRestartDate = createDateObject(
          event.get().extra?.[GLEAN_REFERENCE_TIME_EXTRA_KEY]
        );
        const dateOffset = nextRestartDate.getTime() - lastRestartDate.getTime();
        lastRestartDate = nextRestartDate;

        // Calculate the new offset since new restart.
        const newRestartedOffset = restartedOffset + dateOffset;

        // The restarted event is always timestamp 0,
        // so in order to guarantee event timestamps are always in ascending order,
        // the offset needs to be _at least_ larger than the previous timestamp.
        const previousEventTimestamp = sortedEvents[index - 1].get().timestamp;
        if (newRestartedOffset <= previousEventTimestamp) {
          // In case the new offset results in descending timestamps,
          // we increase the previous timestamp by one to make sure
          // timestamps keep increasing.
          restartedOffset = previousEventTimestamp + 1;
          Context.errorManager.record(
            getGleanRestartedEventMetric([pingName]),
            ErrorType.InvalidValue,
            `Invalid time offset between application sessions found for ping "${pingName}". Ignoring.`
          );
        } else {
          restartedOffset = newRestartedOffset;
        }
      } catch {
        // Do nothing,
        // this is expected to fail in case the current event is not a `glean.restarted` event.
      }

      // Apply necessary offsets to timestamps:
      // 1. If it is the first execution, subtract the firstEventOffset;
      // 2. Otherwise add restartedOffset.

      // The execution counter is a counter metric, the smallest value it can have is `1`.
      // At this stage all metrics should have an execution counter, but out of caution we
      // will fallback to `1` in case it is not present.
      const executionCount = Number(event.get().extra?.[GLEAN_EXECUTION_COUNTER_EXTRA_KEY] || 1);
      let adjustedTimestamp: number;
      if (executionCount === 1) {
        adjustedTimestamp = event.get().timestamp - firstEventOffset;
      } else {
        adjustedTimestamp = event.get().timestamp + restartedOffset;
      }

      sortedEvents[index] = new RecordedEvent({
        category: event.get().category,
        name: event.get().name,
        timestamp: adjustedTimestamp,
        extra: event.get().extra
      });
    }

    // There is no additional context in trailing `glean.restarted` events, they can be removed.
    sortedEvents = removeTrailingRestartedEvents(sortedEvents);

    return sortedEvents.map((e) => e.payload());
  }