Skip to content
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

proxy timings#1717

Merged
merged 14 commits into from
May 29, 2018
Merged

proxy timings #1717

merged 14 commits into from
May 29, 2018

Conversation

i110
Copy link
Contributor

@i110 i110 commented Mar 30, 2018

Add a logging feature to log access timings to upstream servers

  • %{proxy-idle-time}x
  • %{proxy-connect-time}x
  • %{proxy-request-header-time}x
  • %{proxy-request-body-time}x
  • %{proxy-request-total-time}x
  • %{proxy-first-byte-time}x
  • %{proxy-response-time}x
  • %{proxy-total-time}x

TODO:

  • more granularity? (i.e. upstream-request-header-time, etc) It might needs some interface changes of http1client..
  • server-timings header
  • tests

@i110 i110 changed the title [WIP] upstream timing logs proxy timing logs Mar 30, 2018
@i110 i110 changed the title proxy timing logs proxy timings Mar 30, 2018
Copy link
Member

@kazuho kazuho left a comment

Choose a reason for hiding this comment

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

Thank you for working on this. I like the general approach proposed by the PR.

IIRC, the outcome of our discussion was that we will simply emit timing information of the upstream side (i.e. h2o acting as a client), rather than trying to build a generic framework to handle timing information. However, I see some part of the code trying to provide abstraction that seems to contradict with the decision.

Could you please clarify why they are necessary?

include/h2o.h Outdated
*/
struct {
h2o_proxy_log_data_t *proxy;
} handler_log_data;
Copy link
Member

Choose a reason for hiding this comment

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

Two questions here:

  • does proxy need to be a pointer?
  • do we need to wrap h2o_proxy_log_data_t with a struct named handler_log_data? I'd assume that the timing information we will be logging directly in h2o to be i) when the information is sent to the client and ii) when the information is generated by the generator. If my assumption is true, then we will have nothing other than proxy.

uint64_t request_end_at;
uint64_t response_start_at;
uint64_t response_end_at;
} h2o_http1client_timings_t;
Copy link
Member

Choose a reason for hiding this comment

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

LGTM.

LAST_ELEMENT()->data.handler_cb = cb;
goto MAP_EXT_Found;
}

Copy link
Member

Choose a reason for hiding this comment

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

Can't we simply add ELEMENT_TYPE_PROXY_PROCESS_TIME etc. due to the same reason stated above?

@i110
Copy link
Contributor Author

i110 commented Apr 4, 2018

Thank you for your comment. As you said I added a little abstraction because

  1. I wanted to encapsulate actual logging logics in proxy.c. I anticipated that additional demands of logging like upstream-addr or upstream-status in nginx will be raised soonly. If that happen logconf.c will get too completed to maintain unless this encapsulating I think
  2. other handler might want to add logging values in the future. %{mruby.foo}x or %{file.bar}x may be useful sometime

@kazuho
Copy link
Member

kazuho commented Apr 4, 2018

Thank you for the answer.

The problem as I see is that the abstraction is incomplete. For example, existence of handler-specific type (i.e. h2o_req_t::handler_log_data.proxy) means that the feature is not handler-agnostic, while some of the functions (e.g. logger callbacks) are tried to be abstracted.

I also wonder it would be the right approach to let the handler define a dedicated callback for each log specifier would be the right approach for a genenic mechanism. For example, you might want to generate an arbitrary-named property in the mruby handler. But you cannot dynamically create a callback that binds to the named property.

In other words, I am backwards against trying to design a framework at the moment when there is no clear need for one.

@i110
Copy link
Contributor Author

i110 commented Apr 4, 2018

the feature is not handler-agnostic, while some of the functions (e.g. logger callbacks) are tried to be abstracted.

I agree, it's sort of like result of compromise. I don't have objection to removing handler_log_data struct

For example, you might want to generate an arbitrary-named property in the mruby handler. But you cannot dynamically create a callback that binds to the named property.

In such a case, for example, mruby handler can catch mruby- prefix and run the callback written in mruby. Only thing I wanted to do is encapsulating the logics in each handlers, not developing framework.

@i110
Copy link
Contributor Author

i110 commented Apr 4, 2018

@kazuho I addressed the issues and add tests.

include/h2o.h Outdated
/**
* proxy log data
*/
h2o_http1client_timings_t *proxy_timings;
Copy link
Member

Choose a reason for hiding this comment

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

Thank you for the changes.

How about adding h2o_http1client_timings_t (not a pointer) as a member of h2o_req_t::timestamps?

By doing so, I believe that we can drastically reduce the changes. For example, there would be no need for new functions like h2o_proxy_time_compute_.... All we need to do in core is to support new variables in logconf.c.

@i110
Copy link
Contributor Author

i110 commented Apr 13, 2018

@kazuho Thank you for your comment. I addressed the issues.

Copy link
Member

@kazuho kazuho left a comment

Choose a reason for hiding this comment

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

Thank you for the changes. Aside from the comment below I think that the code is ready for merge.

lib/core/util.c Outdated
DELIMITER ELEMENT_LONGEST_STR("process") DELIMITER ELEMENT_LONGEST_STR("proxy-idle") \
DELIMITER ELEMENT_LONGEST_STR("proxy-connect") DELIMITER ELEMENT_LONGEST_STR("proxy-request-header") \
DELIMITER ELEMENT_LONGEST_STR("proxy-request-body") DELIMITER ELEMENT_LONGEST_STR("proxy-request-total") \
DELIMITER ELEMENT_LONGEST_STR("proxy-first-byte")
Copy link
Member

Choose a reason for hiding this comment

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

Do these field names match those that are actually being emitted?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

oops, thank you for finding this. Fixed at 06b4a9b
And also I found similar bug exists in h2o_build_server_timing_trailer, then I fixed it at ce33863

lib/core/util.c Outdated
prefix_len + suffix_len + sizeof(ELEMENT_LONGEST_STR(response) DELIMITER ELEMENT_LONGEST_STR(total)));
value.base = h2o_mem_alloc_pool(&req->pool, *value.base,
prefix_len + suffix_len +
sizeof(ELEMENT_LONGEST_STR("response") DELIMITER ELEMENT_LONGEST_STR("total")));
Copy link
Member

Choose a reason for hiding this comment

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

Do we have enough space here now that we might also be sending timings for proxy-response and proxy-total?

@kazuho kazuho merged commit 5597dbe into master May 29, 2018
@kazuho
Copy link
Member

kazuho commented May 29, 2018

Thank you for the changes. Merged to master.

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.

2 participants