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

Get matched route information #822

Open
cortopy opened this issue Jun 28, 2024 · 2 comments
Open

Get matched route information #822

cortopy opened this issue Jun 28, 2024 · 2 comments

Comments

@cortopy
Copy link

cortopy commented Jun 28, 2024

Is your feature request related to a problem? Please describe.

When a Request is processed, I need to log which route is being handled. The Opentelemetry definition of route is very handy:

The matched route, that is, the path template in the format used by the respective server framework.

And they give examples like: /users/:userID?, {controller}/{action}/{id?}

I need this because:

  • When searching log records, I don't want to search for /user/123 but /user/<id> since I may want to see requests for that route.
  • Some observability providers like Grafana cloud charge per cardinality, and logging requests with variable parameters can be very expensive.
  • Due to privacy legistlation like GDPR, identifiable information like user ids need to be removed or masked. Having a way to know if the Request has been matched with a route that has parameters would be great.
  • Opentelemetry defines http.route as an established convention to log which server route a given request has been matched with.

Describe the solution you'd like
It'd be amazing if Request or Response had something like:

struct RouteInformation {
   path: &str
}

impl RouteInformation {
  pub fn masked_uri() -> String {
     // Some logic to replace parameters with something lkike ****
  }
}

struct Request {
   route: RouteInformation,
   ...
}
#[async_trait]
impl Handler for Logger {
    async fn handle(
        &self,
        req: &mut Request,
        depot: &mut Depot,
        res: &mut Response,
        ctrl: &mut FlowCtrl,
    ) {
        let span = info_span!(
            "Request",
            // Instead of: path = %req.uri(),
            url.path = %req.route.masked(),
            http.route = %req.route.path(),
        );

        async move {
            let now = Instant::now();
            ctrl.call_next(req, depot, res).await;
            let duration = now.elapsed();

            let status = res.status_code.unwrap_or(match &res.body {
                ResBody::None => StatusCode::NOT_FOUND,
                ResBody::Error(e) => e.code,
                _ => StatusCode::OK,
            });
            info!(
                http.response.status_code = %status,
                http.duration = ?duration,
                "Response"
            );
        }
        .instrument(span)
        .await
    }
}

Describe alternatives you've considered
Request doesn't provide information about routes so it would be some laborious manual process for each known route. This would be prone to error.

@chrislearn
Copy link
Member

Any other web framework has this feature?

@immno
Copy link
Contributor

immno commented Nov 12, 2024

I see that Axum seems to have achieved it.
doc
axum issues

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants