Fix Graphite Tag integration - #131
Conversation
f89d7e2 to
8f70419
Compare
Fix data generation script to send required fields nit remove non graphite changes nit Add datagen changes Fails still but can deploy local code Set defaults for all variables and manually specify pub_time Add table on supported metadata field nit Only confirm pub_time is set properly
ec4a46e to
adc9f02
Compare
|
@Gerrrr Can you take a look here |
Gerrrr
left a comment
There was a problem hiding this comment.
Thanks for opening this PR, @sarthaksin1857 ! I found a few things we need to fix before it is ready to merge. Also, given the wealth of subtle issues, this class may deserve a few unit tests.
| filter data by commit or version using `--since-commit` or `--since-version` selectors. | ||
|
|
||
| #### Supported Metadata Schema | ||
| The following keys are supported within the `data` dictionary: |
There was a problem hiding this comment.
It may not be clear what is the data dictionary in this case. In the paragraph above, we talk about tags, so I suggest replacing this statement with The following tags are supported:
| if isinstance(self.pub_time, str): | ||
| self.pub_time = parse_datetime(self.pub_time) | ||
| elif isinstance(self.pub_time, (int, float)): | ||
| self.pub_time = datetime.fromtimestamp(self.pub_time) |
There was a problem hiding this comment.
This change uses a different parsing logic than parse_datetime. The latter does dateparser.parse(date, settings={"RETURN_AS_TIMEZONE_AWARE": True}).
Why do need these extra manipulations with pub_time? I don't follow how making fields optional required it.
There was a problem hiding this comment.
This was more just me looking at this code an how to future proof it.
The function says that pub_time is already a date time and if its already a datetime, why try to parse it again?
Similarly if someone passes in a unix int like 1776522767 the string function wont work either
So before we passed in an integer string as "datetime" and then parsed it back into a string, and then into the proper object.
I will just move the logic into parse_datetime and make this code cleaner
| self.version = None | ||
| else: | ||
| self.version = version | ||
| if len(branch) == 0 or branch == "null": |
There was a problem hiding this comment.
This logic was lost in this PR. If a string text is empty or equal to "null", we still want to treat it as empty, unless there is a reason not to.
There was a problem hiding this comment.
Since I switched all actual "optional" fields to be optional, I will clean all of them (except pub_time)
| end_time: int, | ||
| version: Optional[str], | ||
| branch: Optional[str], | ||
| commit: Optional[str], |
There was a problem hiding this comment.
idea (maybe outside of scope of this PR): today, if we have other event tags like "environment": "prod", we'll crash with unexpected keyword argument. Maybe we can change this class such that it'd work arbitrary tags.
There was a problem hiding this comment.
Yea I wonder if we should even define fields here as "supported tags" and rather just store them in a map and print them all at the end as columns
There was a problem hiding this comment.
I like this idea! Again, it is not required in this PR, but is worth doing in a follow-up.
a76be64 to
2b019bf
Compare
documentation fixup Address comments Add coverage for parsing Clean all string Indentation nit formatter Auto formatter
c0ea484 to
19e758c
Compare
|
@Gerrrr sorry for the wait this is ready for another pass. I made it so
I tried to extend the integration tests but it didn't seem to play well with tags. Whenever I tried sending an event, it would time out (I can file an issue for adding integration coverage and tackle that next?) |
Gerrrr
left a comment
There was a problem hiding this comment.
Apologies for the long review cycle. This PR is almost ready - just a few small things to fix. Can you also paste the WIP integration test that timed out for you? Maybe I'll be able to help out with it.
| if isinstance(date, (int, float)): | ||
| return datetime.fromtimestamp(date, tz=timezone.utc) | ||
|
|
||
| if isinstance(date, str): |
There was a problem hiding this comment.
This method supports strings, ints, floats, datetime now. However, all its callers are using str(input), so there are no callers at all that benefit from this change.
While I am not asking to refactor callers of this method across the entire codebase, do you think it would make sense to use it in Graphite importer? If not... then what's the point of this change?
| return None | ||
|
|
||
| if not isinstance(value, str): | ||
| return value # or raise TypeError if you want strictness |
There was a problem hiding this comment.
This return violates the type signature. I'd throw a type error.
| end_time: int, | ||
| version: Optional[str], | ||
| branch: Optional[str], | ||
| commit: Optional[str], |
There was a problem hiding this comment.
I like this idea! Again, it is not required in this PR, but is worth doing in a follow-up.
| if self.pub_time is None: | ||
| raise ValueError("pub_time is required and cannot be None") | ||
| # Ensure pub_time is always a datetime | ||
| self.pub_time = parse_datetime(str(self.pub_time)) |
There was a problem hiding this comment.
I think we should do parse_datetime on start_time and date_time. If they are None, they will remain None. If they are strings/ints, they will get converted to datetime. Without this change, we may get arbitrary types in those fields. Example:
def test_graphite_event_parses_start_and_end_time():
"""start_time and end_time are documented as supported tags and annotated
Optional[datetime]; if Graphite delivers them as Unix timestamps (int) or
ISO strings in the event data, they must be normalized to tz-aware
datetimes, the same way pub_time is."""
event = GraphiteEvent(
pub_time=1700000000,
start_time=1700000000,
end_time="2024-01-01 10:00:00",
)
assert isinstance(event.start_time, datetime)
assert event.start_time.tzinfo is not None
assert isinstance(event.end_time, datetime)
assert event.end_time.tzinfo is not None
#24
What
Proof it works
With the graphite example in the repo, we now see
Which makes sense as we do not set
runbut we do set everything else