Skip to content

Commit

Permalink
Add InstrumentLayer and InstrumentPlugin
Browse files Browse the repository at this point in the history
  • Loading branch information
Harry Barber committed Sep 20, 2022
1 parent 4b26e49 commit 46ffa8f
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 0 deletions.
65 changes: 65 additions & 0 deletions rust-runtime/aws-smithy-http-server/src/logging/layer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

use tower::Layer;

use super::{InstrumentOperation, MakeIdentity};

/// A [`Layer`] used to apply [`InstrumentOperation`].
#[derive(Debug)]
pub struct InstrumentLayer<RequestMakeFmt = MakeIdentity, ResponseMakeFmt = MakeIdentity> {
operation_name: &'static str,
make_request: RequestMakeFmt,
make_response: ResponseMakeFmt,
}

impl InstrumentLayer {
/// Constructs a new [`InstrumentLayer`] with no data redacted.
pub fn new(operation_name: &'static str) -> Self {
Self {
operation_name,
make_request: MakeIdentity,
make_response: MakeIdentity,
}
}
}

impl<RequestMakeFmt, ResponseMakeFmt> InstrumentLayer<RequestMakeFmt, ResponseMakeFmt> {
/// Configures the request format.
///
/// The argument is typically [`RequestFmt`](super::sensitivity::RequestFmt).
pub fn request_fmt<R>(self, make_request: R) -> InstrumentLayer<R, ResponseMakeFmt> {
InstrumentLayer {
operation_name: self.operation_name,
make_request,
make_response: self.make_response,
}
}

/// Configures the response format.
///
/// The argument is typically [`ResponseFmt`](super::sensitivity::ResponseFmt).
pub fn response_fmt<R>(self, make_response: R) -> InstrumentLayer<RequestMakeFmt, R> {
InstrumentLayer {
operation_name: self.operation_name,
make_request: self.make_request,
make_response,
}
}
}

impl<S, RequestMakeFmt, ResponseMakeFmt> Layer<S> for InstrumentLayer<RequestMakeFmt, ResponseMakeFmt>
where
RequestMakeFmt: Clone,
ResponseMakeFmt: Clone,
{
type Service = InstrumentOperation<S, RequestMakeFmt, ResponseMakeFmt>;

fn layer(&self, service: S) -> Self::Service {
InstrumentOperation::new(service, self.operation_name)
.request_fmt(self.make_request.clone())
.response_fmt(self.make_response.clone())
}
}
4 changes: 4 additions & 0 deletions rust-runtime/aws-smithy-http-server/src/logging/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,15 @@
//!
//! [sensitive trait]: https://awslabs.github.io/smithy/1.0/spec/core/documentation-traits.html?highlight=sensitive%20trait#sensitive-trait
mod layer;
mod plugin;
pub mod sensitivity;
mod service;

use std::fmt::{Debug, Display};

pub use layer::*;
pub use plugin::*;
pub use service::*;

/// A standard interface for taking some component of the HTTP request/response and transforming it into new struct
Expand Down
47 changes: 47 additions & 0 deletions rust-runtime/aws-smithy-http-server/src/logging/plugin.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

use tower::layer::util::Stack;

use crate::{
operation::{Operation, OperationShape},
plugin::{Pluggable, Plugin},
};

use super::{layer::InstrumentLayer, sensitivity::Sensitivity};

/// An [`Plugin`] which applies [`InstrumentLayer`] to all operations in the builder.
#[derive(Debug)]
pub struct InstrumentPlugin;

impl<P, Op, S, L> Plugin<P, Op, S, L> for InstrumentPlugin
where
Op: OperationShape,
Op: Sensitivity,
{
type Service = S;
type Layer = Stack<L, InstrumentLayer<Op::RequestFmt, Op::ResponseFmt>>;

fn map(&self, operation: Operation<S, L>) -> Operation<Self::Service, Self::Layer> {
let layer = InstrumentLayer::new(Op::NAME)
.request_fmt(Op::request_fmt())
.response_fmt(Op::response_fmt());
operation.layer(layer)
}
}

/// An extension trait for applying [`InstrumentLayer`] to all operations.
pub trait InstrumentExt: Pluggable<InstrumentPlugin> {
/// Applies [`InstrumentLayer`] to all operations. See [`InstrumentOperation`](super::InstrumentOperation) for more
/// information.
fn instrument(self) -> Self::Output
where
Self: Sized,
{
self.apply(InstrumentPlugin)
}
}

impl<Builder> InstrumentExt for Builder where Builder: Pluggable<InstrumentPlugin> {}
18 changes: 18 additions & 0 deletions rust-runtime/aws-smithy-http-server/src/logging/sensitivity/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,27 @@ mod response;
mod sensitive;
pub mod uri;

use http::{HeaderMap, StatusCode, Uri};
pub use request::*;
pub use response::*;
pub use sensitive::*;

use super::{MakeDebug, MakeDisplay};

/// The string placeholder for redacted data.
pub const REDACTED: &str = "{redacted}";

/// An interface for providing [`MakeDebug`] and [`MakeDisplay`] for [`Request`](http::Request) and
/// [`Response`](http::Response).
pub trait Sensitivity {
/// The [`MakeDebug`] and [`MakeDisplay`] for the request [`HeaderMap`] and [`Uri`].
type RequestFmt: for<'a> MakeDebug<&'a HeaderMap> + for<'a> MakeDisplay<&'a Uri>;
/// The [`MakeDebug`] and [`MakeDisplay`] for the response [`HeaderMap`] and [`Uri`].
type ResponseFmt: for<'a> MakeDebug<&'a HeaderMap> + MakeDisplay<StatusCode>;

/// Returns the [`RequestFmt`](Sensitivity::RequestFmt).
fn request_fmt() -> Self::RequestFmt;

/// Returns the [`ResponseFmt`](Sensitivity::ResponseFmt).
fn response_fmt() -> Self::ResponseFmt;
}

0 comments on commit 46ffa8f

Please sign in to comment.