blob: 9c0c20af2217dc78111256eabea94752cc97ad28 [file] [log] [blame]
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001/*
2 *
Craig Tiller06059952015-02-18 08:34:56 -08003 * Copyright 2015, Google Inc.
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08004 * 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) {
Craig Tiller87d5b192015-04-16 14:37:57 -070065 grpc_linked_mdelem* m;
Craig Tiller9c9d4e02015-04-20 09:03:29 -070066 for (m = op->data.metadata.list.head; m != NULL; m = m->next) {
Craig Tiller6902ad22015-04-16 08:01:49 -070067 if (m->md->key == chand->path_str) {
Craig Tiller9c9d4e02015-04-20 09:03:29 -070068 gpr_log(GPR_DEBUG, "%s", (const char*)GPR_SLICE_START_PTR(m->md->value->slice));
Craig Tiller87d5b192015-04-16 14:37:57 -070069 census_add_method_tag(
70 calld->op_id, (const char*)GPR_SLICE_START_PTR(m->md->value->slice));
Craig Tiller6902ad22015-04-16 08:01:49 -070071 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080072 }
73}
74
ctillerf962f522014-12-10 15:28:27 -080075static void client_call_op(grpc_call_element* elem,
76 grpc_call_element* from_elem, grpc_call_op* op) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080077 call_data* calld = elem->call_data;
78 channel_data* chand = elem->channel_data;
79 GPR_ASSERT(calld != NULL);
80 GPR_ASSERT(chand != NULL);
hongyu24200d32015-01-08 15:13:49 -080081 GPR_ASSERT((calld->op_id.upper != 0) || (calld->op_id.lower != 0));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080082 switch (op->type) {
83 case GRPC_SEND_METADATA:
84 extract_and_annotate_method_tag(op, calld, chand);
85 break;
86 case GRPC_RECV_FINISH:
87 /* Should we stop timing the rpc here? */
88 break;
89 default:
90 break;
91 }
92 /* Always pass control up or down the stack depending on op->dir */
93 grpc_call_next_op(elem, op);
94}
95
ctillerf962f522014-12-10 15:28:27 -080096static void server_call_op(grpc_call_element* elem,
97 grpc_call_element* from_elem, grpc_call_op* op) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080098 call_data* calld = elem->call_data;
99 channel_data* chand = elem->channel_data;
100 GPR_ASSERT(calld != NULL);
101 GPR_ASSERT(chand != NULL);
hongyu24200d32015-01-08 15:13:49 -0800102 GPR_ASSERT((calld->op_id.upper != 0) || (calld->op_id.lower != 0));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800103 switch (op->type) {
104 case GRPC_RECV_METADATA:
105 extract_and_annotate_method_tag(op, calld, chand);
106 break;
107 case GRPC_SEND_FINISH:
108 /* Should we stop timing the rpc here? */
109 break;
110 default:
111 break;
112 }
113 /* Always pass control up or down the stack depending on op->dir */
114 grpc_call_next_op(elem, op);
115}
116
ctillerf962f522014-12-10 15:28:27 -0800117static void channel_op(grpc_channel_element* elem,
118 grpc_channel_element* from_elem, grpc_channel_op* op) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800119 switch (op->type) {
120 case GRPC_TRANSPORT_CLOSED:
121 /* TODO(hongyu): Annotate trace information for all calls of the channel
122 */
123 break;
124 default:
125 break;
126 }
127 grpc_channel_next_op(elem, op);
128}
129
130static void client_init_call_elem(grpc_call_element* elem,
131 const void* server_transport_data) {
132 call_data* d = elem->call_data;
133 GPR_ASSERT(d != NULL);
134 init_rpc_stats(&d->stats);
135 d->start_ts = gpr_now();
136 d->op_id = census_tracing_start_op();
137}
138
139static void client_destroy_call_elem(grpc_call_element* elem) {
140 call_data* d = elem->call_data;
141 GPR_ASSERT(d != NULL);
142 census_record_rpc_client_stats(d->op_id, &d->stats);
143 census_tracing_end_op(d->op_id);
144}
145
146static void server_init_call_elem(grpc_call_element* elem,
147 const void* server_transport_data) {
148 call_data* d = elem->call_data;
149 GPR_ASSERT(d != NULL);
150 init_rpc_stats(&d->stats);
151 d->start_ts = gpr_now();
152 d->op_id = census_tracing_start_op();
153}
154
155static void server_destroy_call_elem(grpc_call_element* elem) {
156 call_data* d = elem->call_data;
157 GPR_ASSERT(d != NULL);
158 d->stats.elapsed_time_ms =
159 gpr_timespec_to_micros(gpr_time_sub(gpr_now(), d->start_ts));
160 census_record_rpc_server_stats(d->op_id, &d->stats);
161 census_tracing_end_op(d->op_id);
162}
163
164static void init_channel_elem(grpc_channel_element* elem,
165 const grpc_channel_args* args, grpc_mdctx* mdctx,
166 int is_first, int is_last) {
167 channel_data* chand = elem->channel_data;
168 GPR_ASSERT(chand != NULL);
169 GPR_ASSERT(!is_first);
170 GPR_ASSERT(!is_last);
171 chand->path_str = grpc_mdstr_from_string(mdctx, ":path");
172}
173
hongyu24200d32015-01-08 15:13:49 -0800174static void destroy_channel_elem(grpc_channel_element* elem) {
175 channel_data* chand = elem->channel_data;
176 GPR_ASSERT(chand != NULL);
177 if (chand->path_str != NULL) {
178 grpc_mdstr_unref(chand->path_str);
179 }
180}
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800181
182const grpc_channel_filter grpc_client_census_filter = {
Craig Tiller87d5b192015-04-16 14:37:57 -0700183 client_call_op, channel_op, sizeof(call_data), client_init_call_elem,
184 client_destroy_call_elem, sizeof(channel_data), init_channel_elem,
185 destroy_channel_elem, "census-client"};
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800186
187const grpc_channel_filter grpc_server_census_filter = {
Craig Tiller87d5b192015-04-16 14:37:57 -0700188 server_call_op, channel_op, sizeof(call_data), server_init_call_elem,
189 server_destroy_call_elem, sizeof(channel_data), init_channel_elem,
190 destroy_channel_elem, "census-server"};