Skip to content

Commit c81811b

Browse files
committed
add server instrumentation for method calls
1 parent 7c53f68 commit c81811b

File tree

6 files changed

+180
-13
lines changed

6 files changed

+180
-13
lines changed

Cargo.toml

+8
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,14 @@ path = "examples/hello_world/client.rs"
4848
name = "greeter_server"
4949
path = "examples/hello_world/server.rs"
5050

51+
[[example]]
52+
name = "greeter_client_instrument"
53+
path = "examples/hello_world_instrument/client.rs"
54+
55+
[[example]]
56+
name = "greeter_server_instrument"
57+
path = "examples/hello_world_instrument/server.rs"
58+
5159
[dev-dependencies]
5260
serde_json = "1.0"
5361
serde = "1.0"

compiler/src/codegen.rs

+42-12
Original file line numberDiff line numberDiff line change
@@ -379,24 +379,35 @@ impl<'a> MethodGen<'a> {
379379
w.fn_def(&sig);
380380
}
381381

382-
fn write_bind(&self, w: &mut CodeWriter) {
382+
fn write_bind(&self, w: &mut CodeWriter, instrument: bool) {
383383
let add = match self.method_type().0 {
384384
MethodType::Unary => "add_unary_handler",
385385
MethodType::ClientStreaming => "add_client_streaming_handler",
386386
MethodType::ServerStreaming => "add_server_streaming_handler",
387387
MethodType::Duplex => "add_duplex_streaming_handler",
388388
};
389-
w.block(
390-
&format!(
391-
"builder = builder.{}(&{}, move |ctx, req, resp| {{",
392-
add,
393-
self.const_method_name()
394-
),
395-
"});",
396-
|w| {
397-
w.write_line(&format!("instance.{}(ctx, req, resp)", self.name()));
398-
},
389+
390+
let line = &format!(
391+
"builder = builder.{}(&{}, move |ctx, req, resp| {{",
392+
add,
393+
self.const_method_name()
399394
);
395+
396+
if instrument {
397+
w.block(line, "});", |w| {
398+
w.write_line("&p.before();");
399+
w.write_line(&format!(
400+
"let res = instance.{}(ctx, req, resp);",
401+
self.name()
402+
));
403+
w.write_line("&p.after();");
404+
w.write_line("res");
405+
});
406+
} else {
407+
w.block(line, "});", |w| {
408+
w.write_line(&format!("instance.{}(ctx, req, resp)", self.name()));
409+
});
410+
}
400411
}
401412
}
402413

@@ -489,7 +500,26 @@ impl<'a> ServiceGen<'a> {
489500
w.write_line("let mut builder = ::grpcio::ServiceBuilder::new();");
490501
for method in &self.methods {
491502
w.write_line("let mut instance = s.clone();");
492-
method.write_bind(w);
503+
method.write_bind(w, false);
504+
}
505+
w.write_line("builder.build()");
506+
});
507+
508+
// server with instrumentation
509+
w.write_line("");
510+
511+
let s = format!(
512+
"create_instrumented_{}<S: {} + Send + Clone + 'static, P: {} + Clone + Send + Copy + 'static>(s: S, p: P) -> {}",
513+
to_snake_case(&self.service_name()),
514+
self.service_name(),
515+
fq_grpc("ServerInstrumenter"),
516+
fq_grpc("Service")
517+
);
518+
w.pub_fn(&s, |w| {
519+
w.write_line("let mut builder = ::grpcio::ServiceBuilder::new();");
520+
for method in &self.methods {
521+
w.write_line("let mut instance = s.clone();");
522+
method.write_bind(w, true);
493523
}
494524
w.write_line("builder.build()");
495525
});
+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright 2017 PingCAP, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
extern crate grpcio;
15+
extern crate grpcio_proto;
16+
#[macro_use]
17+
extern crate log;
18+
19+
#[path = "../log_util.rs"]
20+
mod log_util;
21+
22+
use std::sync::Arc;
23+
24+
use grpcio::{ChannelBuilder, EnvBuilder};
25+
use grpcio_proto::example::helloworld::HelloRequest;
26+
use grpcio_proto::example::helloworld_grpc::GreeterClient;
27+
28+
fn main() {
29+
let _guard = log_util::init_log(None);
30+
let env = Arc::new(EnvBuilder::new().build());
31+
let ch = ChannelBuilder::new(env).connect("localhost:50051");
32+
let client = GreeterClient::new(ch);
33+
34+
let mut req = HelloRequest::new();
35+
req.set_name("world".to_owned());
36+
let reply = client.say_hello(&req).expect("rpc");
37+
info!("Greeter received: {}", reply.get_message());
38+
}
+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// Copyright 2017 PingCAP, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
extern crate futures;
15+
extern crate grpcio;
16+
extern crate grpcio_proto;
17+
#[macro_use]
18+
extern crate log;
19+
20+
#[path = "../log_util.rs"]
21+
mod log_util;
22+
23+
use std::io::Read;
24+
use std::sync::Arc;
25+
use std::{io, thread};
26+
27+
use futures::sync::oneshot;
28+
use futures::Future;
29+
use grpcio::{Environment, RpcContext, ServerBuilder, ServerInstrumenter, UnarySink};
30+
31+
use grpcio_proto::example::helloworld::{HelloReply, HelloRequest};
32+
use grpcio_proto::example::helloworld_grpc::{self, Greeter};
33+
34+
#[derive(Clone)]
35+
struct GreeterService;
36+
37+
impl Greeter for GreeterService {
38+
fn say_hello(&mut self, ctx: RpcContext, req: HelloRequest, sink: UnarySink<HelloReply>) {
39+
let msg = format!("Hello {}", req.get_name());
40+
let mut resp = HelloReply::new();
41+
resp.set_message(msg);
42+
let f = sink
43+
.success(resp)
44+
.map_err(move |e| error!("failed to reply {:?}: {:?}", req, e));
45+
ctx.spawn(f)
46+
}
47+
}
48+
49+
#[derive(Copy, Clone)]
50+
struct MyServerInstrumenter;
51+
52+
impl ServerInstrumenter for MyServerInstrumenter {
53+
fn before(&self) {
54+
println!("Hello world!");
55+
}
56+
57+
fn after(&self) {
58+
println!("Goodbye.");
59+
}
60+
}
61+
62+
fn main() {
63+
let _guard = log_util::init_log(None);
64+
let env = Arc::new(Environment::new(1));
65+
let service =
66+
helloworld_grpc::create_instrumented_greeter(GreeterService, MyServerInstrumenter);
67+
let mut server = ServerBuilder::new(env)
68+
.register_service(service)
69+
.bind("127.0.0.1", 50_051)
70+
.build()
71+
.unwrap();
72+
server.start();
73+
for &(ref host, port) in server.bind_addrs() {
74+
info!("listening on {}:{}", host, port);
75+
}
76+
let (tx, rx) = oneshot::channel();
77+
thread::spawn(move || {
78+
info!("Press ENTER to exit...");
79+
let _ = io::stdin().read(&mut [0]).unwrap();
80+
tx.send(())
81+
});
82+
let _ = rx.wait();
83+
let _ = server.shutdown().wait();
84+
}

src/lib.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,6 @@ pub use crate::env::{EnvBuilder, Environment};
8383
pub use crate::error::{Error, Result};
8484
pub use crate::log_util::redirect_log;
8585
pub use crate::metadata::{Metadata, MetadataBuilder, MetadataIter};
86-
pub use crate::server::{Server, ServerBuilder, Service, ServiceBuilder, ShutdownFuture};
86+
pub use crate::server::{
87+
Server, ServerBuilder, ServerInstrumenter, Service, ServiceBuilder, ShutdownFuture,
88+
};

src/server.rs

+5
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ impl<F> Handler<F> {
4747
}
4848
}
4949

50+
pub trait ServerInstrumenter {
51+
fn before(&self);
52+
fn after(&self);
53+
}
54+
5055
pub trait CloneableHandler: Send {
5156
fn handle(&mut self, ctx: RpcContext, reqs: Option<MessageReader>);
5257
fn box_clone(&self) -> Box<CloneableHandler>;

0 commit comments

Comments
 (0)