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

feat: Add tower integration #356

Merged
merged 5 commits into from
Aug 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ members = [
"sentry-log",
"sentry-panic",
"sentry-slog",
"sentry-tower",
"sentry-tracing",
"sentry-types",
]
26 changes: 26 additions & 0 deletions sentry-tower/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[package]
name = "sentry-tower"
version = "0.23.0"
authors = ["Sentry <hello@sentry.io>"]
license = "Apache-2.0"
readme = "README.md"
repository = "https://github.com/getsentry/sentry-rust"
homepage = "https://sentry.io/welcome/"
description = """
Sentry integration for tower-based crates.
"""
edition = "2018"

[dependencies]
tower-layer = "0.3"
tower-service = "0.3"
sentry-core = { version = "0.23.0", path = "../sentry-core", default-features = false, features = ["client"] }

[dev-dependencies]
anyhow = "1"
prost = "0.8"
sentry = { version = "0.23.0", path = "../sentry", default-features = false, features = ["test"] }
sentry-anyhow = { version = "0.23.0", path = "../sentry-anyhow" }
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
tonic = { version = "0.5", features = ["transport"] }
tower = { version = "0.4", features = ["util", "timeout"] }
214 changes: 214 additions & 0 deletions sentry-tower/src/helloworld.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
// Autogenerated from tonic's example proto files using `tonic-build`.
//
// Source proto files can be found at
// https://github.com/hyperium/tonic/blob/master/examples/proto/helloworld/helloworld.proto

/// The request message containing the user's name.
Swatinem marked this conversation as resolved.
Show resolved Hide resolved
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct HelloRequest {
#[prost(string, tag = "1")]
pub name: ::prost::alloc::string::String,
}
/// The response message containing the greetings
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct HelloReply {
#[prost(string, tag = "1")]
pub message: ::prost::alloc::string::String,
}
#[doc = r" Generated client implementations."]
pub mod greeter_client {
#![allow(unused_variables, dead_code, missing_docs)]
use tonic::codegen::*;
#[doc = " The greeting service definition."]
#[derive(Debug, Clone)]
pub struct GreeterClient<T> {
inner: tonic::client::Grpc<T>,
}
impl GreeterClient<tonic::transport::Channel> {
#[doc = r" Attempt to create a new client by connecting to a given endpoint."]
pub async fn connect<D>(dst: D) -> Result<Self, tonic::transport::Error>
where
D: std::convert::TryInto<tonic::transport::Endpoint>,
D::Error: Into<StdError>,
{
let conn = tonic::transport::Endpoint::new(dst)?.connect().await?;
Ok(Self::new(conn))
}
}
impl<T> GreeterClient<T>
where
T: tonic::client::GrpcService<tonic::body::BoxBody>,
T::ResponseBody: Body + Send + Sync + 'static,
T::Error: Into<StdError>,
<T::ResponseBody as Body>::Error: Into<StdError> + Send,
{
pub fn new(inner: T) -> Self {
let inner = tonic::client::Grpc::new(inner);
Self { inner }
}
pub fn with_interceptor<F>(
inner: T,
interceptor: F,
) -> GreeterClient<InterceptedService<T, F>>
where
F: FnMut(tonic::Request<()>) -> Result<tonic::Request<()>, tonic::Status>,
T: Service<
http::Request<tonic::body::BoxBody>,
Response = http::Response<
<T as tonic::client::GrpcService<tonic::body::BoxBody>>::ResponseBody,
>,
>,
<T as Service<http::Request<tonic::body::BoxBody>>>::Error:
Into<StdError> + Send + Sync,
{
GreeterClient::new(InterceptedService::new(inner, interceptor))
}
#[doc = r" Compress requests with `gzip`."]
#[doc = r""]
#[doc = r" This requires the server to support it otherwise it might respond with an"]
#[doc = r" error."]
pub fn send_gzip(mut self) -> Self {
self.inner = self.inner.send_gzip();
self
}
#[doc = r" Enable decompressing responses with `gzip`."]
pub fn accept_gzip(mut self) -> Self {
self.inner = self.inner.accept_gzip();
self
}
#[doc = " Sends a greeting"]
pub async fn say_hello(
&mut self,
request: impl tonic::IntoRequest<super::HelloRequest>,
) -> Result<tonic::Response<super::HelloReply>, tonic::Status> {
self.inner.ready().await.map_err(|e| {
tonic::Status::new(
tonic::Code::Unknown,
format!("Service was not ready: {}", e.into()),
)
})?;
let codec = tonic::codec::ProstCodec::default();
let path = http::uri::PathAndQuery::from_static("/helloworld.Greeter/SayHello");
self.inner.unary(request.into_request(), path, codec).await
}
}
}
#[doc = r" Generated server implementations."]
pub mod greeter_server {
#![allow(unused_variables, dead_code, missing_docs)]
use tonic::codegen::*;
#[doc = "Generated trait containing gRPC methods that should be implemented for use with GreeterServer."]
#[async_trait]
pub trait Greeter: Send + Sync + 'static {
#[doc = " Sends a greeting"]
async fn say_hello(
&self,
request: tonic::Request<super::HelloRequest>,
) -> Result<tonic::Response<super::HelloReply>, tonic::Status>;
}
#[doc = " The greeting service definition."]
#[derive(Debug)]
pub struct GreeterServer<T: Greeter> {
inner: _Inner<T>,
accept_compression_encodings: (),
send_compression_encodings: (),
}
struct _Inner<T>(Arc<T>);
impl<T: Greeter> GreeterServer<T> {
pub fn new(inner: T) -> Self {
let inner = Arc::new(inner);
let inner = _Inner(inner);
Self {
inner,
accept_compression_encodings: Default::default(),
send_compression_encodings: Default::default(),
}
}
pub fn with_interceptor<F>(inner: T, interceptor: F) -> InterceptedService<Self, F>
where
F: FnMut(tonic::Request<()>) -> Result<tonic::Request<()>, tonic::Status>,
{
InterceptedService::new(Self::new(inner), interceptor)
}
}
impl<T, B> Service<http::Request<B>> for GreeterServer<T>
where
T: Greeter,
B: Body + Send + Sync + 'static,
B::Error: Into<StdError> + Send + 'static,
{
type Response = http::Response<tonic::body::BoxBody>;
type Error = Never;
type Future = BoxFuture<Self::Response, Self::Error>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, req: http::Request<B>) -> Self::Future {
let inner = self.inner.clone();
match req.uri().path() {
"/helloworld.Greeter/SayHello" => {
#[allow(non_camel_case_types)]
struct SayHelloSvc<T: Greeter>(pub Arc<T>);
impl<T: Greeter> tonic::server::UnaryService<super::HelloRequest> for SayHelloSvc<T> {
type Response = super::HelloReply;
type Future = BoxFuture<tonic::Response<Self::Response>, tonic::Status>;
fn call(
&mut self,
request: tonic::Request<super::HelloRequest>,
) -> Self::Future {
let inner = self.0.clone();
let fut = async move { (*inner).say_hello(request).await };
Box::pin(fut)
}
}
let accept_compression_encodings = self.accept_compression_encodings;
let send_compression_encodings = self.send_compression_encodings;
let inner = self.inner.clone();
let fut = async move {
let inner = inner.0;
let method = SayHelloSvc(inner);
let codec = tonic::codec::ProstCodec::default();
let mut grpc = tonic::server::Grpc::new(codec).apply_compression_config(
accept_compression_encodings,
send_compression_encodings,
);
let res = grpc.unary(method, req).await;
Ok(res)
};
Box::pin(fut)
}
_ => Box::pin(async move {
Ok(http::Response::builder()
.status(200)
.header("grpc-status", "12")
.header("content-type", "application/grpc")
.body(empty_body())
.unwrap())
}),
}
}
}
impl<T: Greeter> Clone for GreeterServer<T> {
fn clone(&self) -> Self {
let inner = self.inner.clone();
Self {
inner,
accept_compression_encodings: self.accept_compression_encodings,
send_compression_encodings: self.send_compression_encodings,
}
}
}
impl<T: Greeter> Clone for _Inner<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<T: std::fmt::Debug> std::fmt::Debug for _Inner<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.0)
}
}
impl<T: Greeter> tonic::transport::NamedService for GreeterServer<T> {
const NAME: &'static str = "helloworld.Greeter";
}
}
Loading