blob: 2799bded8a6e4d0a054de64e9be89ef56cb391d0 [file] [log] [blame]
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001/*
2 *
3 * Copyright 2014, Google Inc.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
34#include "src/core/channel/census_filter.h"
35
36#include <stdio.h>
37#include <string.h>
38
39#include "src/core/channel/channel_stack.h"
40#include "src/core/channel/noop_filter.h"
41#include "src/core/statistics/census_interface.h"
42#include "src/core/statistics/census_rpc_stats.h"
43#include <grpc/support/alloc.h>
44#include <grpc/support/log.h>
45#include <grpc/support/slice.h>
46#include <grpc/support/time.h>
47
48typedef struct call_data {
49 census_op_id op_id;
50 census_rpc_stats stats;
51 gpr_timespec start_ts;
52} call_data;
53
54typedef struct channel_data {
55 grpc_mdstr* path_str; /* pointer to meta data str with key == ":path" */
56} channel_data;
57
58static void init_rpc_stats(census_rpc_stats* stats) {
59 memset(stats, 0, sizeof(census_rpc_stats));
60 stats->cnt = 1;
61}
62
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080063static void extract_and_annotate_method_tag(grpc_call_op* op, call_data* calld,
64 channel_data* chand) {
65 if (op->data.metadata->key == chand->path_str) {
hongyu24200d32015-01-08 15:13:49 -080066 gpr_log(GPR_DEBUG,
67 (const char*)GPR_SLICE_START_PTR(op->data.metadata->value->slice));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080068 census_add_method_tag(calld->op_id, (const char*)GPR_SLICE_START_PTR(
69 op->data.metadata->value->slice));
70 }
71}
72
ctillerf962f522014-12-10 15:28:27 -080073static void client_call_op(grpc_call_element* elem,
74 grpc_call_element* from_elem, grpc_call_op* op) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080075 call_data* calld = elem->call_data;
76 channel_data* chand = elem->channel_data;
77 GPR_ASSERT(calld != NULL);
78 GPR_ASSERT(chand != NULL);
hongyu24200d32015-01-08 15:13:49 -080079 GPR_ASSERT((calld->op_id.upper != 0) || (calld->op_id.lower != 0));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080080 switch (op->type) {
81 case GRPC_SEND_METADATA:
82 extract_and_annotate_method_tag(op, calld, chand);
83 break;
84 case GRPC_RECV_FINISH:
85 /* Should we stop timing the rpc here? */
86 break;
87 default:
88 break;
89 }
90 /* Always pass control up or down the stack depending on op->dir */
91 grpc_call_next_op(elem, op);
92}
93
ctillerf962f522014-12-10 15:28:27 -080094static void server_call_op(grpc_call_element* elem,
95 grpc_call_element* from_elem, grpc_call_op* op) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080096 call_data* calld = elem->call_data;
97 channel_data* chand = elem->channel_data;
98 GPR_ASSERT(calld != NULL);
99 GPR_ASSERT(chand != NULL);
hongyu24200d32015-01-08 15:13:49 -0800100 GPR_ASSERT((calld->op_id.upper != 0) || (calld->op_id.lower != 0));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800101 switch (op->type) {
102 case GRPC_RECV_METADATA:
103 extract_and_annotate_method_tag(op, calld, chand);
104 break;
105 case GRPC_SEND_FINISH:
106 /* Should we stop timing the rpc here? */
107 break;
108 default:
109 break;
110 }
111 /* Always pass control up or down the stack depending on op->dir */
112 grpc_call_next_op(elem, op);
113}
114
ctillerf962f522014-12-10 15:28:27 -0800115static void channel_op(grpc_channel_element* elem,
116 grpc_channel_element* from_elem, grpc_channel_op* op) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800117 switch (op->type) {
118 case GRPC_TRANSPORT_CLOSED:
119 /* TODO(hongyu): Annotate trace information for all calls of the channel
120 */
121 break;
122 default:
123 break;
124 }
125 grpc_channel_next_op(elem, op);
126}
127
128static void client_init_call_elem(grpc_call_element* elem,
129 const void* server_transport_data) {
130 call_data* d = elem->call_data;
131 GPR_ASSERT(d != NULL);
132 init_rpc_stats(&d->stats);
133 d->start_ts = gpr_now();
134 d->op_id = census_tracing_start_op();
135}
136
137static void client_destroy_call_elem(grpc_call_element* elem) {
138 call_data* d = elem->call_data;
139 GPR_ASSERT(d != NULL);
140 census_record_rpc_client_stats(d->op_id, &d->stats);
141 census_tracing_end_op(d->op_id);
142}
143
144static void server_init_call_elem(grpc_call_element* elem,
145 const void* server_transport_data) {
146 call_data* d = elem->call_data;
147 GPR_ASSERT(d != NULL);
148 init_rpc_stats(&d->stats);
149 d->start_ts = gpr_now();
150 d->op_id = census_tracing_start_op();
151}
152
153static void server_destroy_call_elem(grpc_call_element* elem) {
154 call_data* d = elem->call_data;
155 GPR_ASSERT(d != NULL);
156 d->stats.elapsed_time_ms =
157 gpr_timespec_to_micros(gpr_time_sub(gpr_now(), d->start_ts));
158 census_record_rpc_server_stats(d->op_id, &d->stats);
159 census_tracing_end_op(d->op_id);
160}
161
162static void init_channel_elem(grpc_channel_element* elem,
163 const grpc_channel_args* args, grpc_mdctx* mdctx,
164 int is_first, int is_last) {
165 channel_data* chand = elem->channel_data;
166 GPR_ASSERT(chand != NULL);
167 GPR_ASSERT(!is_first);
168 GPR_ASSERT(!is_last);
169 chand->path_str = grpc_mdstr_from_string(mdctx, ":path");
170}
171
hongyu24200d32015-01-08 15:13:49 -0800172static void destroy_channel_elem(grpc_channel_element* elem) {
173 channel_data* chand = elem->channel_data;
174 GPR_ASSERT(chand != NULL);
175 if (chand->path_str != NULL) {
176 grpc_mdstr_unref(chand->path_str);
177 }
178}
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800179
180const grpc_channel_filter grpc_client_census_filter = {
181 client_call_op, channel_op,
182
183 sizeof(call_data), client_init_call_elem, client_destroy_call_elem,
184
185 sizeof(channel_data), init_channel_elem, destroy_channel_elem,
186
187 "census-client"};
188
189const grpc_channel_filter grpc_server_census_filter = {
190 server_call_op, channel_op,
191
192 sizeof(call_data), server_init_call_elem, server_destroy_call_elem,
193
194 sizeof(channel_data), init_channel_elem, destroy_channel_elem,
195
196 "census-server"};