1 /*
2 * Copyright (c) 2014-2016 DeNA Co., Ltd., Kazuho Oku, Fastly, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to
6 * deal in the Software without restriction, including without limitation the
7 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 * sell copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20 * IN THE SOFTWARE.
21 */
22 #ifndef h2o__probes_h
23 #define h2o__probes_h
24
25 /* This file is placed under lib, and must only be included from the source files of the h2o / libh2o, because H2O_USE_DTRACE is a
26 * symbol available only during the build phase of h2o. That's fine, because only h2o / libh2o has the sole right to define probes
27 * belonging to the h2o namespace.
28 */
29 #if H2O_USE_DTRACE
30
31 #include "picotls.h"
32 /* as probes_.h is used by files under lib/common, structures that are specific to the server-side implementation have to be
33 * forward-declared. */
34 struct st_h2o_conn_t;
35 struct st_h2o_tunnel_t;
36 #include "h2o-probes.h"
37
38 #define H2O_CONN_IS_PROBED(label, conn) (PTLS_UNLIKELY(H2O_##label##_ENABLED()) && !conn->callbacks->skip_tracing(conn))
39
40 #define H2O_PROBE_CONN0(label, conn) \
41 do { \
42 h2o_conn_t *_conn = (conn); \
43 if (H2O_CONN_IS_PROBED(label, _conn)) { \
44 H2O_##label(_conn->id); \
45 } \
46 } while (0)
47
48 #define H2O_PROBE_CONN(label, conn, ...) \
49 do { \
50 h2o_conn_t *_conn = (conn); \
51 if (H2O_CONN_IS_PROBED(label, _conn)) { \
52 H2O_##label(_conn->id, __VA_ARGS__); \
53 } \
54 } while (0)
55
56 #define H2O_PROBE(label, ...) \
57 do { \
58 if (PTLS_UNLIKELY(H2O_##label##_ENABLED())) { \
59 H2O_##label(__VA_ARGS__); \
60 } \
61 } while (0)
62
63 #define H2O_PROBE_HEXDUMP(s, l) \
64 ({ \
65 size_t _l = (l); \
66 ptls_hexdump(alloca(_l * 2 + 1), (s), _l); \
67 })
68
69 #else
70
71 #define H2O_CONN_IS_PROBED(label, conn) (0)
72 #define H2O_PROBE_CONN0(label, conn)
73 #define H2O_PROBE_CONN(label, conn, ...)
74 #define H2O_PROBE(label, ...)
75 #define H2O_PROBE_HEXDUMP(s, l)
76
77 #endif
78
79 /* Helper functions for probing; the functions are defined as non-inlineable, as bcc cannot handle relative offset against a static
80 * const (e.g., H2O_TOKEN_PATH->buf.base). They are available only when h2o.h is included, so that files under lib/common can
81 * include this function without creating dependency against lib/core (e.g., `h2o_req_t`). */
82 #ifdef h2o_h
83
h2o_probe_request_header(h2o_req_t * req,uint64_t req_index,h2o_iovec_t name,h2o_iovec_t value)84 __attribute__((noinline)) static void h2o_probe_request_header(h2o_req_t *req, uint64_t req_index, h2o_iovec_t name,
85 h2o_iovec_t value)
86 {
87 H2O_PROBE_CONN(RECEIVE_REQUEST_HEADER, req->conn, req_index, name.base, name.len, value.base, value.len);
88 }
89
h2o_probe_response_header(h2o_req_t * req,uint64_t req_index,h2o_iovec_t name,h2o_iovec_t value)90 __attribute__((noinline)) static void h2o_probe_response_header(h2o_req_t *req, uint64_t req_index, h2o_iovec_t name,
91 h2o_iovec_t value)
92 {
93 H2O_PROBE_CONN(SEND_RESPONSE_HEADER, req->conn, req_index, name.base, name.len, value.base, value.len);
94 }
95
h2o_probe_log_request(h2o_req_t * req,uint64_t req_index)96 static inline void h2o_probe_log_request(h2o_req_t *req, uint64_t req_index)
97 {
98 H2O_PROBE_CONN(RECEIVE_REQUEST, req->conn, req_index, req->version);
99 if (H2O_CONN_IS_PROBED(RECEIVE_REQUEST_HEADER, req->conn)) {
100 if (req->input.authority.base != NULL)
101 h2o_probe_request_header(req, req_index, H2O_TOKEN_AUTHORITY->buf, req->input.authority);
102 if (req->input.method.base != NULL)
103 h2o_probe_request_header(req, req_index, H2O_TOKEN_METHOD->buf, req->input.method);
104 if (req->input.path.base != NULL)
105 h2o_probe_request_header(req, req_index, H2O_TOKEN_PATH->buf, req->input.path);
106 if (req->input.scheme != NULL)
107 h2o_probe_request_header(req, req_index, H2O_TOKEN_SCHEME->buf, req->input.scheme->name);
108 size_t i;
109 for (i = 0; i != req->headers.size; ++i) {
110 h2o_header_t *h = req->headers.entries + i;
111 h2o_probe_request_header(req, req_index, *h->name, h->value);
112 }
113 }
114 }
115
h2o_probe_log_response(h2o_req_t * req,uint64_t req_index)116 static inline void h2o_probe_log_response(h2o_req_t *req, uint64_t req_index)
117 {
118 H2O_PROBE_CONN(SEND_RESPONSE, req->conn, req_index, req->res.status);
119 if (H2O_CONN_IS_PROBED(SEND_RESPONSE_HEADER, req->conn)) {
120 if (req->res.content_length != SIZE_MAX) {
121 char buf[sizeof(H2O_SIZE_T_LONGEST_STR)];
122 size_t len = (size_t)sprintf(buf, "%zu", req->res.content_length);
123 h2o_probe_response_header(req, req_index, H2O_TOKEN_CONTENT_LENGTH->buf, h2o_iovec_init(buf, len));
124 }
125 size_t i;
126 for (i = 0; i != req->res.headers.size; ++i) {
127 h2o_header_t *h = req->res.headers.entries + i;
128 h2o_probe_response_header(req, req_index, *h->name, h->value);
129 }
130 }
131 }
132
133 #endif
134
135 #endif
136