{"id":13570150,"url":"https://github.com/Depado/ginprom","last_synced_at":"2025-04-04T06:31:57.379Z","repository":{"id":46054244,"uuid":"106262733","full_name":"depado/ginprom","owner":"depado","description":"Gin Prometheus metrics exporter","archived":false,"fork":false,"pushed_at":"2025-03-31T20:26:08.000Z","size":207,"stargazers_count":158,"open_issues_count":4,"forks_count":38,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-01T10:09:23.337Z","etag":null,"topics":["gin","instrumentation","metrics","middleware","prometheus"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/depado.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-10-09T09:23:22.000Z","updated_at":"2025-03-25T17:25:47.000Z","dependencies_parsed_at":"2024-01-09T16:56:45.217Z","dependency_job_id":"3e9fbde0-adaf-45ba-909c-c1289e048a9e","html_url":"https://github.com/depado/ginprom","commit_stats":{"total_commits":116,"total_committers":23,"mean_commits":5.043478260869565,"dds":0.6379310344827587,"last_synced_commit":"3060e46ac2cd48d5169d557beaeee1b469ac489b"},"previous_names":[],"tags_count":26,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/depado%2Fginprom","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/depado%2Fginprom/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/depado%2Fginprom/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/depado%2Fginprom/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/depado","download_url":"https://codeload.github.com/depado/ginprom/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246620222,"owners_count":20806722,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["gin","instrumentation","metrics","middleware","prometheus"],"created_at":"2024-08-01T14:00:48.881Z","updated_at":"2025-04-04T06:31:52.354Z","avatar_url":"https://github.com/depado.png","language":"Go","readme":"\u003ch1 align=\"center\"\u003eGinprom\u003c/h1\u003e\n\u003ch2 align=\"center\"\u003e\n\nGin Prometheus metrics exporter\n\n[![Sourcegraph](https://sourcegraph.com/github.com/Depado/ginprom/-/badge.svg)](https://sourcegraph.com/github.com/Depado/ginprom?badge)\n[![Go Report Card](https://goreportcard.com/badge/github.com/Depado/ginprom)](https://goreportcard.com/report/github.com/Depado/ginprom)\n[![Build Status](https://drone.depa.do/api/badges/Depado/ginprom/status.svg)](https://drone.depa.do/Depado/ginprom)\n[![codecov](https://codecov.io/gh/Depado/ginprom/branch/master/graph/badge.svg)](https://codecov.io/gh/Depado/ginprom)\n[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/Depado/bfchroma/blob/master/LICENSE)\n[![godoc](https://godoc.org/github.com/Depado/ginprom?status.svg)](https://godoc.org/github.com/Depado/ginprom)\n\n\u003c/h2\u003e\n\u003ch4 align=\"center\"\u003e\n\nInspired by [github.com/zsais/go-gin-prometheus](https://github.com/zsais/go-gin-prometheus)\n\n\u003c/h4\u003e\n\n- [Install](#install)\n- [Differences with go-gin-prometheus](#differences-with-go-gin-prometheus)\n- [Usage](#usage)\n- [Options](#options)\n\t- [Custom counters](#custom-counters)\n\t- [Custom gauges](#custom-gauges)\n\t- [Custom histograms](#custom-histograms)\n\t- [Path](#path)\n\t- [Namespace](#namespace)\n\t- [Subsystem](#subsystem)\n\t- [Engine](#engine)\n\t- [Prometheus Registry](#prometheus-registry)\n\t- [HandlerNameFunc](#handlernamefunc)\n\t- [RequestPathFunc](#requestpathfunc)\n\t- [CustomCounterLabels](#customcounterlabels)\n\t- [Ignore](#ignore)\n\t- [Token](#token)\n\t- [Bucket size](#bucket-size)\n- [Troubleshooting](#troubleshooting)\n\t- [The instrumentation doesn't seem to work](#the-instrumentation-doesnt-seem-to-work)\n\n## Install\n\nSimply run:\n`go get -u github.com/Depado/ginprom`\n\n## Differences with go-gin-prometheus\n\n- No support for Prometheus' Push Gateway\n- Options on constructor\n- Adds a `path` label to get the matched route\n- Ability to ignore routes\n\n## Usage\n\n```go\npackage main\n\nimport (\n\t\"github.com/Depado/ginprom\"\n\t\"github.com/gin-gonic/gin\"\n)\n\nfunc main() {\n\tr := gin.Default()\n\tp := ginprom.New(\n\t\tginprom.Engine(r),\n\t\tginprom.Subsystem(\"gin\"),\n\t\tginprom.Path(\"/metrics\"),\n\t)\n\tr.Use(p.Instrument())\n\n\tr.GET(\"/hello/:id\", func(c *gin.Context) {})\n\tr.GET(\"/world/:id\", func(c *gin.Context) {})\n\tr.Run(\"127.0.0.1:8080\")\n}\n```\n\n## Options\n\n### Custom counters\n\nAdd custom counters to add own values to the metrics\n\n```go\nr := gin.New()\np := ginprom.New(\n\tginprom.Engine(r),\n)\np.AddCustomCounter(\"custom\", \"Some help text to provide\", []string{\"label\"})\nr.Use(p.Instrument())\n```\n\nSave `p` and use the following functions:\n\n- IncrementCounterValue\n- AddCounterValue\n\n### Custom gauges\n\nAdd custom gauges to add own values to the metrics\n\n```go\nr := gin.New()\np := ginprom.New(\n\tginprom.Engine(r),\n)\np.AddCustomGauge(\"custom\", \"Some help text to provide\", []string{\"label\"})\nr.Use(p.Instrument())\n```\n\nSave `p` and use the following functions:\n\n- IncrementGaugeValue\n- DecrementGaugeValue\n- SetGaugeValue\n\n### Custom histograms\n\nAdd custom histograms to add own values to the metrics\n\n```go\nr := gin.New()\np := ginprom.New(\n  ginprom.Engine(r),\n)\np.AddCustomHistogram(\"internal_request_latency\", \"Duration of internal HTTP requests\", []string{\"url\", \"method\", \"status\"})\nr.Use(p.Instrument())\n```\n\nSave `p` and use the following functions:\n\n- AddCustomHistogramValue\n\n### Path\n\nOverride the default path (`/metrics`) on which the metrics can be accessed:\n\n```go\nr := gin.New()\np := ginprom.New(\n\tginprom.Engine(r),\n\tginprom.Path(\"/custom/metrics\"),\n)\nr.Use(p.Instrument())\n```\n\n### Namespace\n\nOverride the default namespace (`gin`):\n\n```go\nr := gin.New()\np := ginprom.New(\n\tginprom.Engine(r),\n\tginprom.Namespace(\"custom_ns\"),\n)\nr.Use(p.Instrument())\n```\n\n### Subsystem\n\nOverride the default (`gonic`) subsystem:\n\n```go\nr := gin.New()\np := ginprom.New(\n\tginprom.Engine(r),\n\tginprom.Subsystem(\"your_subsystem\"),\n)\nr.Use(p.Instrument())\n```\n\n### Engine\n\nThe preferred way to pass the router to ginprom:\n\n```go\nr := gin.New()\np := ginprom.New(\n\tginprom.Engine(r),\n)\nr.Use(p.Instrument())\n```\n\nThe alternative being to call the `Use` method after initialization:\n\n```go\np := ginprom.New()\n// ...\nr := gin.New()\np.Use(r)\nr.Use(p.Instrument())\n\n```\n\n### Prometheus Registry\n\nUse a custom `prometheus.Registry` instead of prometheus client's global registry. This option allows\nto use ginprom in multiple gin engines in the same process, or if you would like to integrate ginprom with your own\nprometheus `Registry`.\n\n```go\nregistry := prometheus.NewRegistry() // creates new prometheus metric registry\nr := gin.New()\np := ginprom.New(\n    ginprom.Registry(registry),\n)\nr.Use(p.Instrument())\n```\n\n### HandlerNameFunc\n\nChange the way the `handler` label is computed. By default, the `(*gin.Context).HandlerName`\nfunction is used.\nThis option is useful when wanting to group different functions under\nthe same `handler` label or when using `gin` with decorated handlers.\n\n```go\nr := gin.Default()\np := ginprom.New(\n\tHandlerNameFunc(func (c *gin.Context) string {\n\t\treturn \"my handler\"\n\t}),\n)\nr.Use(p.Instrument())\n```\n\n### RequestPathFunc\n\nChange how the `path` label is computed. By default, the `(*gin.Context).FullPath` function\nis used.\nThis option is useful when wanting to group different requests under the same `path`\nlabel or when wanting to process unknown routes (the default `(*gin.Context).FullPath` returns\nan empty string for unregistered routes). Note that requests for which `f` returns the empty\nstring are ignored.\n\nTo specifically ignore certain paths, see the [Ignore](#ignore) option.\n\n```go\nr := gin.Default()\np := ginprom.New(\n\t// record a metric for unregistered routes under the path label \"\u003cunknown\u003e\"\n\tRequestPathFunc(func (c *gin.Context) string {\n\t\tif fullpath := c.FullPath(); fullpath != \"\" {\n\t\t\treturn fullpath\n\t\t}\n\t\treturn \"\u003cunknown\u003e\"\n\t}),\n)\nr.Use(p.Instrument())\n```\n\n### CustomCounterLabels\n\nAdd custom labels to the counter metric.\n\n```go\nr := gin.Default()\np := ginprom.New(\n  ginprom.CustomCounterLabels([]string{\"client_id\"}, func(c *gin.Context) map[string]string {\n    client_id := c.GetHeader(\"x-client-id\")\n    if client_id == \"\" {\n      client_id = \"unknown\"\n    }\n    return map[string]string{\"client_id\": client_id}\n  }),\n)\nr.Use(p.Instrument())\n```\n\n### Ignore\n\nIgnore allows to completely ignore some routes. Even though you can apply the\nmiddleware to the only groups you're interested in, it is sometimes useful to\nhave routes not instrumented.\n\n```go\nr := gin.New()\np := ginprom.New(\n\tginprom.Engine(r),\n\tginprom.Ignore(\"/api/no/no/no\", \"/api/super/secret/route\")\n)\nr.Use(p.Instrument())\n```\n\nNote that most of the time this can be solved by gin groups:\n\n```go\nr := gin.New()\np := ginprom.New(ginprom.Engine(r))\n\n// Add the routes that do not need instrumentation\ng := r.Group(\"/api/\")\ng.Use(p.Instrument())\n{\n\t// Instrumented routes\n}\n```\n\n### Token\n\nSpecify a secret token which Prometheus will use to access the endpoint. If the\ntoken is invalid, the endpoint will return an error.\n\n```go\nr := gin.New()\np := ginprom.New(\n\tginprom.Engine(r),\n\tginprom.Token(\"supersecrettoken\")\n)\nr.Use(p.Instrument())\n```\n\n### Bucket size\n\nSpecify the bucket size for the request duration histogram according to your\nexpected durations.\n\n```go\nr := gin.New()\np := ginprom.New(\n\tginprom.Engine(r),\n\tginprom.BucketSize([]float64{.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10}),\n)\nr.Use(p.Instrument())\n```\n\n## Troubleshooting\n\n### The instrumentation doesn't seem to work\n\nMake sure you have set the `gin.Engine` in the `ginprom` middleware, either when\ninitializing it using `ginprom.New(ginprom.Engine(r))` or using the `Use`\nfunction after the initialization like this :\n\n```go\np := ginprom.New(\n\tginprom.Namespace(\"gin\"),\n\tginprom.Subsystem(\"gonic\"),\n\tginprom.Path(\"/metrics\"),\n)\np.Use(r)\nr.Use(p.Instrument())\n```\n\nBy design, if the middleware was to panic, it would do so when a route is\ncalled. That's why it just silently fails when no engine has been set.\n","funding_links":[],"categories":["Go"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FDepado%2Fginprom","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FDepado%2Fginprom","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FDepado%2Fginprom/lists"}