You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

158 lines
4.2 KiB

  1. // Copyright 2014 The Macaron Authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License"): you may
  4. // not use this file except in compliance with the License. You may obtain
  5. // a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  11. // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  12. // License for the specific language governing permissions and limitations
  13. // under the License.
  14. // Package toolbox is a middleware that provides health check, pprof, profile and statistic services for Macaron.
  15. package toolbox
  16. import (
  17. "fmt"
  18. "io"
  19. "net/http"
  20. "net/http/pprof"
  21. "path"
  22. "time"
  23. "gitea.com/macaron/macaron"
  24. )
  25. const _VERSION = "0.1.4"
  26. func Version() string {
  27. return _VERSION
  28. }
  29. // Toolbox represents a tool box service for Macaron instance.
  30. type Toolbox interface {
  31. AddHealthCheck(HealthChecker)
  32. AddHealthCheckFunc(string, HealthCheckFunc)
  33. AddStatistics(string, string, time.Duration)
  34. GetMap(io.Writer)
  35. JSON(io.Writer)
  36. }
  37. type toolbox struct {
  38. *UrlMap
  39. healthCheckJobs []*healthCheck
  40. }
  41. // Options represents a struct for specifying configuration options for the Toolbox middleware.
  42. type Options struct {
  43. // URL prefix for toolbox dashboard. Default is "/debug".
  44. URLPrefix string
  45. // URL for health check request. Default is "/healthcheck".
  46. HealthCheckURL string
  47. // Health checkers.
  48. HealthCheckers []HealthChecker
  49. // Health check functions.
  50. HealthCheckFuncs []*HealthCheckFuncDesc
  51. // URL for URL map json. Default is "/urlmap.json".
  52. URLMapPrefix string
  53. // DisableDebug turns off all debug functionality.
  54. DisableDebug bool
  55. // URL prefix of pprof. Default is "/debug/pprof/".
  56. PprofURLPrefix string
  57. // URL prefix of profile. Default is "/debug/profile/".
  58. ProfileURLPrefix string
  59. // Path store profile files. Default is "profile".
  60. ProfilePath string
  61. }
  62. var opt Options
  63. func prepareOptions(options []Options) {
  64. if len(options) > 0 {
  65. opt = options[0]
  66. }
  67. // Defaults.
  68. if len(opt.URLPrefix) == 0 {
  69. opt.URLPrefix = "/debug"
  70. }
  71. if len(opt.HealthCheckURL) == 0 {
  72. opt.HealthCheckURL = "/healthcheck"
  73. }
  74. if len(opt.URLMapPrefix) == 0 {
  75. opt.URLMapPrefix = "/urlmap.json"
  76. }
  77. if len(opt.PprofURLPrefix) == 0 {
  78. opt.PprofURLPrefix = "/debug/pprof/"
  79. } else if opt.PprofURLPrefix[len(opt.PprofURLPrefix)-1] != '/' {
  80. opt.PprofURLPrefix += "/"
  81. }
  82. if len(opt.ProfileURLPrefix) == 0 {
  83. opt.ProfileURLPrefix = "/debug/profile/"
  84. } else if opt.ProfileURLPrefix[len(opt.ProfileURLPrefix)-1] != '/' {
  85. opt.ProfileURLPrefix += "/"
  86. }
  87. if len(opt.ProfilePath) == 0 {
  88. opt.ProfilePath = path.Join(macaron.Root, "profile")
  89. }
  90. }
  91. func dashboard() string {
  92. return fmt.Sprintf(`<p>Toolbox Index:</p>
  93. <ol>
  94. <li><a href="%s">Pprof Information</a></li>
  95. <li><a href="%s">Profile Operations</a></li>
  96. </ol>`, opt.PprofURLPrefix, opt.ProfileURLPrefix)
  97. }
  98. var _ Toolbox = &toolbox{}
  99. // Toolboxer is a middleware provides health check, pprof, profile and statistic services for your application.
  100. func Toolboxer(m *macaron.Macaron, options ...Options) macaron.Handler {
  101. prepareOptions(options)
  102. t := &toolbox{
  103. healthCheckJobs: make([]*healthCheck, 0, len(opt.HealthCheckers)+len(opt.HealthCheckFuncs)),
  104. }
  105. // Dashboard.
  106. m.Get(opt.URLPrefix, dashboard)
  107. // Health check.
  108. for _, hc := range opt.HealthCheckers {
  109. t.AddHealthCheck(hc)
  110. }
  111. for _, fd := range opt.HealthCheckFuncs {
  112. t.AddHealthCheckFunc(fd.Desc, fd.Func)
  113. }
  114. m.Route(opt.HealthCheckURL, "HEAD,GET", t.handleHealthCheck)
  115. // URL map.
  116. m.Get(opt.URLMapPrefix, func(rw http.ResponseWriter) {
  117. t.JSON(rw)
  118. })
  119. if !opt.DisableDebug {
  120. // Pprof
  121. m.Any(path.Join(opt.PprofURLPrefix, "cmdline"), pprof.Cmdline)
  122. m.Any(path.Join(opt.PprofURLPrefix, "profile"), pprof.Profile)
  123. m.Any(path.Join(opt.PprofURLPrefix, "symbol"), pprof.Symbol)
  124. m.Any(opt.PprofURLPrefix, pprof.Index)
  125. m.Any(path.Join(opt.PprofURLPrefix, "*"), pprof.Index)
  126. // Profile
  127. profilePath = opt.ProfilePath
  128. m.Get(opt.ProfileURLPrefix, handleProfile)
  129. }
  130. // Routes statistic.
  131. t.UrlMap = &UrlMap{
  132. urlmap: make(map[string]map[string]*Statistics),
  133. }
  134. return func(ctx *macaron.Context) {
  135. ctx.MapTo(t, (*Toolbox)(nil))
  136. }
  137. }