Skip to content

Conversation

@TingDaoK
Copy link
Contributor

@TingDaoK TingDaoK commented Mar 29, 2023

  • Support get the telemetry after each single request

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

*/
struct aws_s3_request_telemetry_metrics {
/* X-AMZ-REQUEST-ID Header value. */
struct aws_byte_cursor request_id;
Copy link
Contributor

Choose a reason for hiding this comment

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

we're already passing all the response headers, we don't need this

Copy link
Contributor Author

Choose a reason for hiding this comment

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

just want to have a simple way to fetch the request id instead of fetching it from the headers.

@codecov-commenter
Copy link

codecov-commenter commented Mar 31, 2023

Codecov Report

Merging #271 (a8ee7e4) into main (ea78cb6) will increase coverage by 0.36%.
The diff coverage is 94.88%.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #271      +/-   ##
==========================================
+ Coverage   87.52%   87.88%   +0.36%     
==========================================
  Files          16       16              
  Lines        4103     4316     +213     
==========================================
+ Hits         3591     3793     +202     
- Misses        512      523      +11     
Impacted Files Coverage Δ
source/s3.c 96.15% <ø> (ø)
source/s3_util.c 98.64% <ø> (ø)
source/s3_request.c 95.02% <93.67%> (-4.98%) ⬇️
source/s3_client.c 87.35% <100.00%> (+0.04%) ⬆️
source/s3_meta_request.c 94.51% <100.00%> (+0.27%) ⬆️

@TingDaoK TingDaoK marked this pull request as ready for review April 13, 2023 17:34
/**
* Information sent in the meta_request telemetry callback.
*/
struct aws_s3_request_metrics {
Copy link
Contributor

Choose a reason for hiding this comment

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

should we expose extra things like num_parts, bytes_transferred?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

num_parts is included in the request_path_query, bytes_transferred can be interesting, but most likely will be the part size.

Copy link
Contributor

Choose a reason for hiding this comment

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

maybe i dont understand what request_path_query is, but how would it include num parts?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For put parts, it will have the part number in it, but, for multipart get, it is not.

I'll add the part number to be easier for the user

Copy link
Contributor Author

Choose a reason for hiding this comment

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

But, for multipart get, we were actually doing ranged-get, which is different from get parts. I guess it can be confused to the user as well.

uint64_t send_end_timestamp_ns;
/* The time duration for the request from start encoding to finish encoding (send_end_timestamp_ns -
* send_start_timestamp_ns). When send_end_timestamp_ns is 0, means data not available. */
uint64_t sending_duration_ns;
Copy link
Contributor

Choose a reason for hiding this comment

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

Did we decide on #271 (comment)? I think it would be nice to be consistent with http layer.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In my opinion, the reason we used int64_t to have the data unavailable easy to check, but we provide the getters with error, so I guess it will make more sense for those value to be unsigned, as they should never less than zero.

AWS_S3_API
void aws_s3_request_metrics_get_request_path_query(
const struct aws_s3_request_metrics *metrics,
struct aws_byte_cursor *out_request_path_query);
Copy link
Contributor

Choose a reason for hiding this comment

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

trivial: I would use aws_string for these string properties, instead of aws_byte_cursor/aws_byte_buf

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Why? I think we have the metrics as the object holding all the data, so this is the getter to fetch the data from the object, will it be better to use aws_byte_cursor?

Copy link
Contributor

Choose a reason for hiding this comment

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

aws_string is null-terminated, which makes is easier if the user wants to pass it along to things like printf() or other old-fashioned C calls that expect a null-terminated string

Copy link
Contributor

Choose a reason for hiding this comment

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

Additionally, it is easier to reason about the lifetime of aws_string. With a byte_cursor, users must also ensure that the underlying memory is not freed until the lifetime of the byte_cursor.

Copy link
Contributor

Choose a reason for hiding this comment

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

I was still proposing the same sketchy lifetime as we'd get with aws_byte_cursor, where we just give them a pointer to the internal data and warn them about lifetimes

Comment on lines 281 to 284
if (metrics->time_metrics.receive_end_timestamp_ns == 0 || metrics->time_metrics.receive_start_timestamp_ns == 0) {
return aws_raise_error(AWS_ERROR_S3_METRIC_DATA_NOT_AVAILABLE);
}
*receiving_duration = metrics->time_metrics.receiving_duration_ns;
Copy link
Contributor

Choose a reason for hiding this comment

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

wouldn't it be less error_prone to continue storing times as int64_t internally, so we could simply use -1 to indicate date not available?

Suggested change
if (metrics->time_metrics.receive_end_timestamp_ns == 0 || metrics->time_metrics.receive_start_timestamp_ns == 0) {
return aws_raise_error(AWS_ERROR_S3_METRIC_DATA_NOT_AVAILABLE);
}
*receiving_duration = metrics->time_metrics.receiving_duration_ns;
if (metrics->time_metrics.receiving_duration_ns < 0) {
return aws_raise_error(AWS_ERROR_S3_METRIC_DATA_NOT_AVAILABLE);
}
*receiving_duration = (uint64_t)metrics->time_metrics.receiving_duration_ns;

vs doing this thing where 0 maaay be valid from some values, so we better consult two other values

like we were doing in that "Range: 0-0" bug we just had

Comment on lines 716 to 722
/* Get the request ID from aws_s3_request_metrics, AWS_ERROR_S3_METRIC_DATA_NOT_AVAILABLE will be raised when data
* unavailable */
AWS_S3_API
int aws_s3_request_metrics_get_request_id(
struct aws_allocator *allocator,
const struct aws_s3_request_metrics *metrics,
struct aws_string **out_request_id);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
/* Get the request ID from aws_s3_request_metrics, AWS_ERROR_S3_METRIC_DATA_NOT_AVAILABLE will be raised when data
* unavailable */
AWS_S3_API
int aws_s3_request_metrics_get_request_id(
struct aws_allocator *allocator,
const struct aws_s3_request_metrics *metrics,
struct aws_string **out_request_id);
/**
* Get the request ID from aws_s3_request_metrics.
* If unavailable, AWS_ERROR_S3_METRIC_DATA_NOT_AVAILABLE will be raised.
* If available, out_request_id will be set to a string. Be warned this string's lifetime is tied to the metrics object.
*/
AWS_S3_API
int aws_s3_request_metrics_get_request_id(
const struct aws_s3_request_metrics *metrics,
const struct aws_string **out_request_id);
// OR return NULL and raise error if unavailable
const struct aws_string *aws_s3_request_metrics_get_request_id(
const struct aws_s3_request_metrics *metrics);

I wasn't suggesting we allocate a new string every time someone queries, I was suggesting storing these internally as aws_string (instead of aws_byte_buf), and just handing out the pointer from the query

If all this rigamarole about using aws_string instead of aws_byte_cursor is more trouble than it's worth, then just roll back to using aws_byte_cursor. this was a debatable suggestion to begin with

Copy link
Contributor

@graebm graebm left a comment

Choose a reason for hiding this comment

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

fix & ship

Comment on lines +435 to +436
* Notes:
* - The callback will be invoked multiple times from different threads.
Copy link
Member

Choose a reason for hiding this comment

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

including concurrently?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes


/**
* Optional.
* To get telemetry metrics when a single request finishes.
Copy link
Member

Choose a reason for hiding this comment

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

is this guaranteed to only be invoked before the finish_callback?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes

Comment on lines 824 to 826
/* Get the part number of the request, if the request is not associated with a part, error code will be raised. */
AWS_S3_API
int aws_s3_request_metrics_get_part_number(const struct aws_s3_request_metrics *metrics, uint32_t *out_part_number);
Copy link
Member

Choose a reason for hiding this comment

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

Is it possible to get the range of the part for auto-ranged gets?

Copy link
Contributor Author

@TingDaoK TingDaoK May 10, 2023

Choose a reason for hiding this comment

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

yes, but the response header should have content-range in it, and covers the range of the part for the request.

I think we can just remove it for now, the part number is confusing for auto-ranged get. And for auto-put we can get the information from the aws_s3_request_metrics_get_request_path_query

Comment on lines +809 to +811
void aws_s3_request_metrics_get_request_path_query(
const struct aws_s3_request_metrics *metrics,
const struct aws_string **out_request_path_query);
Copy link
Member

Choose a reason for hiding this comment

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

Can we get the type of request this way (GetObject/HeadObject/UploadPart/etc)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll add the type of request in a follow up PR to be more clear

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@TingDaoK TingDaoK merged commit 634d5b0 into main May 11, 2023
@TingDaoK TingDaoK deleted the telemetry-api branch May 11, 2023 16:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants