-
Notifications
You must be signed in to change notification settings - Fork 7.9k
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 in context #748
Comments
You could use |
So |
@Depado could you please give an example? |
Hey there Let's say I have this code : package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func mymiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// There ?
c.Next()
}
}
func main() {
r := gin.New()
r.GET("/user/:id", mymiddleware(), func(c *gin.Context) {
// How can I get the litteral string "/user/:id" here ?
c.JSON(http.StatusOK, gin.H{"message": "received request"})
})
} Is there a way I can retrieve inside the handler the litteral string |
Why won't you just keep it in a constant and so you'll have it as a variable. I mean, if the function runs, it means that it matched the pattern |
Sure but that means there's no generic way of getting the matched pattern in the handler and possibly automate stuff. I'd like to add this as a prometheus label. What I came up with is a middleware that takes this pattern as an argument, making it redundant |
Again, I can't really understand your problem. Routes are pre-defined, they're not dynamically created. Therefore, if a route is matched then it means that you know which router is being used. I could see it being a problem which is necessary to solve on a larger scale. An easy solution would be to provide the matched route via Context. Maybe you could create a pull request with this feature? |
I'd love to if I had time ^^ I'll try to give that a look later. |
Seems like this would require using node.getValue and node.path. node.getValue should either return node.path and bind it to the context or something like that. Or maybe bind the node to the context... |
I do it like this in my prometehus middleware:
|
What's |
gin.Engine
…On Thu, Oct 19, 2017, 16:50 Depado ***@***.***> wrote:
What's p.parent.Routes() ?
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#748 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/ABF-FeXrALCzTR_Jj9W7xjkKHV0xwu0Yks5st2HRgaJpZM4K9F8w>
.
|
I see ! I'll give that a try thanks ! 👍 |
That works fine @jonaz 👍 func (p *Prometheus) Instrument() gin.HandlerFunc {
return func(c *gin.Context) {
var path string
start := time.Now()
reqSz := computeApproximateRequestSize(c.Request)
if c.Request.URL.String() == p.MetricsPath {
c.Next()
return
}
if in, ok := p.PathMap[c.HandlerName()]; ok {
path = in
} else {
// We miss some routes so let's parse that again
for _, ri := range p.Engine.Routes() {
p.PathMap[ri.Handler] = ri.Path
}
if in, ok := p.PathMap[c.HandlerName()]; ok {
path = in
} // If we don't know the path here, then we'll never have it
}
c.Next()
status := strconv.Itoa(c.Writer.Status())
elapsed := float64(time.Since(start)) / float64(time.Second)
resSz := float64(c.Writer.Size())
p.reqDur.Observe(elapsed)
p.reqCnt.WithLabelValues(status, c.Request.Method, c.HandlerName(), c.Request.Host, path).Inc()
p.reqSz.Observe(float64(reqSz))
p.resSz.Observe(resSz)
}
} This way I have a chance to initialize the map when |
i came across same problem, and if do it like you said, must guarantee every route match different handler. |
I ended up re-creating a gin middleware for Prometheus there. I had to use a protected map (that includes a mutex). |
I also had done the same method(redundant function argument) to solve this last year. |
try with gin middleware r.Use(func(c *gin.Context) {
url := c.Request.URL.String()
for _, p := range c.Params {
url = strings.Replace(url, p.Value, ":"+p.Key, 1)
}
c.Set("matched_path", url)
}) then you can get func(c *gin.Context) {
if path, exist := c.Get("matched_path"); exist {
...
}
} |
@tsirolnik the reason for somthing like this is for adding per-api metrics for instance. It's nice to be able to have metrics counts by rest path such as a dimensional metric for: POST /users/:userid/stories/:storyid The current alternative is that you just have a metric per user / storyid combo which isn't super useful. The info needed is in the router and we currently have to either deep inspect into the router to figure that out (some patches on related), or would have to have the middleware know what all the route mappings are and understand that. The Prometheus middleware is a very good example of this. https://github.com/Depado/ginprom/blob/master/prom.go |
Just came across this and wanted to mention another way of achieving this is to declare the "metricName" whilst declaring the endpoint name. This is how we did it prior. So our routes looked like this:
Where the metrics middleware was capturing the latency and sending it to DataDog. |
Is it available? |
PR #1826 adds |
When next version will be released? |
If you're already using a route like then you can well access your matched route through func ProxyToAnotherServer(c *gin.Context) {
relativeRoutePath := c.Param("routePath")
} |
|
I have a use case where the list of exposed apis should be available as an api, where admin user can add some additional parameter for storing to DB.
What I essentially need is to get the matched route in context for processing in middleware or handler function.
So it there some like c.MatchedRoute or some other way to achieve the result?
The text was updated successfully, but these errors were encountered: