Skip to content

Adding more information to LogFileStats + minor updates to tests #31

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Mar 10, 2023

Conversation

eliasyishak
Copy link
Contributor

@eliasyishak eliasyishak commented Mar 8, 2023

This update will include more information for the stats returns from the log file. The following keys have been added

minsFromStartDateTime – how many minutes have elapsed since the oldest log item
minsFromEndDateTime – how many minutes have elapsed since the earliest log item
recordCount – total count of records in the log file
eventCount – a map object that has each event sent as the key and a count of how many times that event was sent

{
    "startDateTime": "2023-02-22 15:23:24.410921",
    "minsFromStartDateTime": 20339,  // NEW
    "endDateTime": "2023-03-08 15:46:36.318211",
    "minsFromEndDateTime": 156,  // NEW
    "sessionCount": 7,
    "flutterChannelCount": 2,
    "toolCount": 1,
    "recordCount": 23,  // NEW
    "eventCount": {  // NEW
        "hot_reload_time": 16,
        "analytics_collection_enabled": 7
    }
}

This will help with survey conditions that involve the presence of an event, count exceeding N for an event being called, etc.

Included in this PR also has local_time in the body of the request to include the timezone offset so that the local time can be used for querying if desired

"local_time": {
  "value": "2023-01-31 14:32:14.592898 -0500"
}

@eliasyishak eliasyishak changed the title Adding more information to LogFileStats Adding more information to LogFileStats + minor updates to tests Mar 9, 2023
@@ -16,9 +17,15 @@ class LogFileStats {
/// The oldest timestamp in the log file
final DateTime startDateTime;

/// Number of minutes from [startDateTime] to [clock.now()]
final int minsFromStartDateTime;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about just storing startDateTime and endDateTime as ints, either from millisecondsSinceEpoch or microsecondsSinceEpoch?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh shoot, I totally forgot that I'm using LogFileStats as a data class essentially. It only appears as a string when you print, or invoke toString() on the entire class. And that was really just for debugging when developing.

So really, when we perform operations with these value, we don't even convert it from ints into DateTime. Thoughts on still leaving it this way?

  @override
  String toString() => jsonEncode(<String, Object?>{
        'startDateTime': startDateTime.toString(),
        'minsFromStartDateTime': minsFromStartDateTime,
        'endDateTime': endDateTime.toString(),
        'minsFromEndDateTime': minsFromEndDateTime,
        'sessionCount': sessionCount,
        'flutterChannelCount': flutterChannelCount,
        'toolCount': toolCount,
        'recordCount': recordCount,
        'eventCount': eventCount,
      });

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh ok, in that case keeping it a DateTime makes sense. However, at what point do we serialize this to disk, and in what format are we serializing these timestamps?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we don't actually serialize anything after the log file stats have been created. This data class will instead be used for checking conditions for a survey and returning a Boolean to show the survey or not.

But these logs are persisted before this step on the user's machine in the same form that they are sent to GA. And in the local log file, it is being persisted as a date time string so that we know the time the user sent the event in their locale. GA also assigns its own time stamp in milliseconds since epoch time in UTC so that all events can be compared chronologically.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's never serialized, how is it part of userProps https://github.com/dart-lang/tools/blob/main/pkgs/unified_analytics/lib/src/log_handler.dart#L226? Isn't that map being read from disk?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the workflow starts with an event sent, and the events usually look like the below being sent in the body of a POST request

{
  "client_id": "46cc0ba6-f604-4fd9-aa2f-8a20beb24cd4",
  "events": [{ "name": "testing", "params": { "time_ns": 345 } }],
  "user_properties": {
    "session_id": { "value": 1673466750423 },
    "flutter_channel": { "value": "ey-test-channel" },
    "host": { "value": "macos" },
    "flutter_version": { "value": "Flutter 3.6.0-7.0.pre.47" },
    "dart_version": { "value": "Dart 2.19.0" },
    "tool": { "value": "flutter-tools" },
    "local_time": { "value": "2023-01-11 14:53:31.471816" }
  }
}

In the above, we do serialize the DateTime to a string in the form yyyy-mm-dd hh:mm:ss.ffff which is the default toString output for a datetime. This is so in GA and BigQuery, we can look at the table and understand the data easily and deserializing within BigQuery is trivial.

Once the event is sent, the entire payload of the POST request is saved into the log file. It is at this point that we read it in and deserialize the string back into a DateTime.

After we have created the LogFileStats data class, we don't serialize that object again. Once we have survey conditions, we will do checks within dart code.

final LogFileStats query = _logHandler.logFileStats();

if (query.toolCount > 2) {
  print('The user has used more than 2 tools');
}

It is only when we print out the query object from above that the data in the class gets serialized again to a string, and this is really for debugging purposes that I included that toString method for LogFileStats

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh ok, never mind, I misread what you said, you said it is persisted because we specifically want it in the user's locale? So GA is expecting a localized string?

Copy link
Contributor Author

@eliasyishak eliasyishak Mar 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, it is. And that's because GA already assigns a timestamp for the event which is in UTC and in milliseconds since epoch time

Also it's not really "expecting" it, we defined the schema of the table to be that way

image

The below also shows how we store the user props data with the local time

image

@eliasyishak eliasyishak marked this pull request as ready for review March 9, 2023 22:30
Copy link
Contributor

@christopherfujino christopherfujino left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@eliasyishak eliasyishak merged commit e5353aa into dart-lang:main Mar 10, 2023
@eliasyishak eliasyishak deleted the more-info-in-log-file-stats branch March 10, 2023 21:35
mosuem pushed a commit that referenced this pull request Aug 13, 2024
Bumps [actions/checkout](https://github.com/actions/checkout) from 3.1.0 to 3.2.0.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@93ea575...755da8c)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants