Compare commits

...

14 Commits

Author SHA1 Message Date
ning
10cc8c2ae8 change extra_info 2023-11-07 16:54:57 +08:00
ning
da54173bd0 refactor event 2023-11-02 21:16:37 +08:00
xtan
9dc20fc674 fix: fix windows dashboard (#1762) 2023-10-27 19:32:23 +08:00
Lars Lehtonen
16430550d1 models: fix clobbered error (#1764) 2023-10-27 19:32:07 +08:00
ning
b34b66785d change notify api perm 2023-10-27 19:22:13 +08:00
ning
2cf38b6027 docs: update built-in linux dashboard 2023-10-27 19:08:46 +08:00
ning
e1b4edaa68 refactor: user-variable-configs api 2023-10-27 18:58:22 +08:00
ning
97f3f70d57 refactor perm api 2023-10-27 18:13:04 +08:00
ning
cee0ce6620 code refactor 2023-10-27 17:40:11 +08:00
ning
89b659695f add ops 2023-10-27 17:35:00 +08:00
Yening Qin
d52848ab1b feat: http support print body log (#1757)
* add log
2023-10-24 11:37:34 +08:00
shardingHe
314a8d71ef Fix:use text template to replace data (#1756)
* add text/template func, avoid escape issues caused by special characters

* rename the function of template

* change use of template. ReplaceTemplateUseHtml replaced to ReplaceTemplateUseText

* change use of template. ReplaceTemplateUseHtml replaced to ReplaceTemplateUseText

---------

Co-authored-by: shardingHe <wangzihe@flashcat.cloud>
2023-10-23 17:22:34 +08:00
shardingHe
bfa85cd8f1 fix: add func for tplx, avoid escape issues caused by special characters (#1755)
* add text/template func, avoid escape issues caused by special characters

* rename the function of template

---------

Co-authored-by: shardingHe <wangzihe@flashcat.cloud>
2023-10-23 16:35:08 +08:00
shardingHe
2254cb1f87 fix: move dashboards to the right place (#1753)
* move dashboards to the right place

* move dashboards to the right place

---------

Co-authored-by: shardingHe <wangzihe@flashcat.cloud>
2023-10-21 11:49:48 +08:00
21 changed files with 311 additions and 1013 deletions

View File

@@ -149,6 +149,11 @@ ops:
- "/user-groups/put"
- "/user-groups/del"
- name: permissions
cname: 权限管理
ops:
- "/permissions"
- name: busi-groups
cname: 业务分组管理
ops:
@@ -160,6 +165,7 @@ ops:
- name: system
cname: 系统信息
ops:
- "/help/variable-configs"
- "/help/version"
- "/help/servers"
- "/help/source"

View File

@@ -367,7 +367,7 @@ func (rt *Router) Config(r *gin.Engine) {
pages.PUT("/role/:id/ops", rt.auth(), rt.admin(), rt.roleBindOperation)
pages.GET("/operation", rt.operations)
pages.GET("/notify-tpls", rt.auth(), rt.admin(), rt.notifyTplGets)
pages.GET("/notify-tpls", rt.auth(), rt.user(), rt.perm("/help/notification-tpls"), rt.notifyTplGets)
pages.PUT("/notify-tpl/content", rt.auth(), rt.admin(), rt.notifyTplUpdateContent)
pages.PUT("/notify-tpl", rt.auth(), rt.admin(), rt.notifyTplUpdate)
pages.POST("/notify-tpl", rt.auth(), rt.admin(), rt.notifyTplAdd)
@@ -377,19 +377,19 @@ func (rt *Router) Config(r *gin.Engine) {
pages.GET("/sso-configs", rt.auth(), rt.admin(), rt.ssoConfigGets)
pages.PUT("/sso-config", rt.auth(), rt.admin(), rt.ssoConfigUpdate)
pages.GET("/webhooks", rt.auth(), rt.admin(), rt.webhookGets)
pages.GET("/webhooks", rt.auth(), rt.user(), rt.webhookGets)
pages.PUT("/webhooks", rt.auth(), rt.admin(), rt.webhookPuts)
pages.GET("/notify-script", rt.auth(), rt.admin(), rt.notifyScriptGet)
pages.GET("/notify-script", rt.auth(), rt.user(), rt.perm("/help/notification-settings"), rt.notifyScriptGet)
pages.PUT("/notify-script", rt.auth(), rt.admin(), rt.notifyScriptPut)
pages.GET("/notify-channel", rt.auth(), rt.admin(), rt.notifyChannelGets)
pages.GET("/notify-channel", rt.auth(), rt.user(), rt.perm("/help/notification-settings"), rt.notifyChannelGets)
pages.PUT("/notify-channel", rt.auth(), rt.admin(), rt.notifyChannelPuts)
pages.GET("/notify-contact", rt.auth(), rt.admin(), rt.notifyContactGets)
pages.GET("/notify-contact", rt.auth(), rt.user(), rt.perm("/help/notification-settings"), rt.notifyContactGets)
pages.PUT("/notify-contact", rt.auth(), rt.admin(), rt.notifyContactPuts)
pages.GET("/notify-config", rt.auth(), rt.admin(), rt.notifyConfigGet)
pages.GET("/notify-config", rt.auth(), rt.user(), rt.perm("/help/notification-settings"), rt.notifyConfigGet)
pages.PUT("/notify-config", rt.auth(), rt.admin(), rt.notifyConfigPut)
pages.PUT("/smtp-config-test", rt.auth(), rt.admin(), rt.attemptSendEmail)
@@ -399,10 +399,10 @@ func (rt *Router) Config(r *gin.Engine) {
pages.PUT("/es-index-pattern", rt.auth(), rt.admin(), rt.esIndexPatternPut)
pages.DELETE("/es-index-pattern", rt.auth(), rt.admin(), rt.esIndexPatternDel)
pages.GET("/user-variable-configs", rt.auth(), rt.admin(), rt.userVariableConfigGets)
pages.POST("/user-variable-config", rt.auth(), rt.admin(), rt.userVariableConfigAdd)
pages.PUT("/user-variable-config/:id", rt.auth(), rt.admin(), rt.userVariableConfigPut)
pages.DELETE("/user-variable-config/:id", rt.auth(), rt.admin(), rt.userVariableConfigDel)
pages.GET("/user-variable-configs", rt.auth(), rt.user(), rt.perm("/help/variable-configs"), rt.userVariableConfigGets)
pages.POST("/user-variable-config", rt.auth(), rt.user(), rt.perm("/help/variable-configs"), rt.userVariableConfigAdd)
pages.PUT("/user-variable-config/:id", rt.auth(), rt.user(), rt.perm("/help/variable-configs"), rt.userVariableConfigPut)
pages.DELETE("/user-variable-config/:id", rt.auth(), rt.user(), rt.perm("/help/variable-configs"), rt.userVariableConfigDel)
pages.GET("/config", rt.auth(), rt.admin(), rt.configGetByKey)
pages.PUT("/config", rt.auth(), rt.admin(), rt.configPutByKey)

View File

@@ -163,7 +163,7 @@ func (rt *Router) notifyConfigPut(c *gin.Context) {
var f models.Configs
ginx.BindJSON(c, &f)
userVariableMap := rt.NotifyConfigCache.ConfigCache.Get()
text := tplx.ReplaceMacroVariables(f.Ckey, f.Cval, userVariableMap)
text := tplx.ReplaceTemplateUseText(f.Ckey, f.Cval, userVariableMap)
switch f.Ckey {
case models.SMTP:
var smtp aconf.SMTPConfig
@@ -221,7 +221,7 @@ func (rt *Router) attemptSendEmail(c *gin.Context) {
ginx.Bomb(200, "config(%v) invalid", f)
}
userVariableMap := rt.NotifyConfigCache.ConfigCache.Get()
text := tplx.ReplaceMacroVariables(f.Ckey, f.Cval, userVariableMap)
text := tplx.ReplaceTemplateUseText(f.Ckey, f.Cval, userVariableMap)
smtp, err := SmtpValidate(text)
ginx.Dangerous(err)

View File

@@ -167,8 +167,10 @@ func (rt *Router) dsProxy(c *gin.Context) {
modifyResponse := func(r *http.Response) error {
if r.StatusCode == http.StatusUnauthorized {
logger.Warningf("proxy path:%s unauthorized access ", c.Request.URL.Path)
return fmt.Errorf("unauthorized access")
}
return nil
}
@@ -180,6 +182,7 @@ func (rt *Router) dsProxy(c *gin.Context) {
}
proxy.ServeHTTP(c.Writer, c.Request)
}
var (

View File

@@ -4,6 +4,7 @@ import (
"net/http"
"strings"
"github.com/ccfos/nightingale/v6/center/cconf"
"github.com/ccfos/nightingale/v6/models"
"github.com/gin-gonic/gin"
@@ -17,6 +18,15 @@ func (rt *Router) rolesGets(c *gin.Context) {
func (rt *Router) permsGets(c *gin.Context) {
user := c.MustGet("user").(*models.User)
if user.IsAdmin() {
var lst []string
for _, ops := range cconf.Operations.Ops {
lst = append(lst, ops.Ops...)
}
ginx.NewRender(c).Data(lst, nil)
return
}
lst, err := models.OperationsOfRole(rt.Ctx, strings.Fields(user.Roles))
ginx.NewRender(c).Data(lst, err)
}

View File

@@ -34,10 +34,15 @@ func (rt *Router) userVariableConfigPut(context *gin.Context) {
ginx.BindJSON(context, &f)
f.Id = ginx.UrlParamInt64(context, "id")
f.Ckey = strings.TrimSpace(f.Ckey)
//update external config. needs to make sure not plaintext for an encrypted type config
//updating with struct it will update all fields ("ckey", "cval", "note", "encrypted", "update_by", "update_at"), not non-zero fields.
f.UpdateBy = context.MustGet("username").(string)
f.UpdateAt = time.Now().Unix()
user := context.MustGet("user").(*models.User)
if !user.IsAdmin() && f.CreateBy != user.Username {
// only admin or creator can update
ginx.Bomb(403, "no permission")
}
ginx.NewRender(context).Message(models.ConfigsUserVariableUpdate(rt.Ctx, f))
}
@@ -46,6 +51,12 @@ func (rt *Router) userVariableConfigDel(context *gin.Context) {
configs, err := models.ConfigGet(rt.Ctx, id)
ginx.Dangerous(err)
user := context.MustGet("user").(*models.User)
if !user.IsAdmin() && configs.CreateBy != user.Username {
// only admin or creator can delete
ginx.Bomb(403, "no permission")
}
if configs != nil && configs.External == models.ConfigExternal {
ginx.NewRender(context).Message(models.ConfigsDel(rt.Ctx, []int64{id}))
} else {

View File

@@ -1,475 +0,0 @@
{
"name": "MSE监控大盘",
"tags": "",
"ident": "MSE-Monitor",
"configs": {
"var": [
{
"name": "datasource",
"type": "datasource",
"definition": "prometheus",
"defaultValue": ""
},
{
"name": "envoy_clusterid",
"label": "envoy_clusterid",
"type": "query",
"hide": false,
"definition": "label_values(envoy_cluster_bind_errors, envoy_clusterid)",
"multi": false,
"datasource": {
"cate": "prometheus",
"value": "${datasource}"
}
}
],
"panels": [
{
"type": "stat",
"id": "aba69dc0-5a11-4bcd-add9-335b5a677bee",
"layout": {
"h": 5,
"w": 6,
"x": 0,
"y": 0,
"i": "aba69dc0-5a11-4bcd-add9-335b5a677bee",
"isResizable": true
},
"version": "3.0.0",
"datasourceCate": "prometheus",
"datasourceValue": 7,
"targets": [
{
"refId": "A",
"expr": "sum(delta(envoy_http_rq_total{envoy_clusterid=\"$envoy_clusterid\"}[1m]))"
}
],
"transformations": [
{
"id": "organize",
"options": {}
}
],
"name": "PV一分钟",
"maxPerRow": 4,
"custom": {
"textMode": "valueAndName",
"graphMode": "none",
"colorMode": "value",
"calc": "lastNotNull",
"valueField": "Value",
"colSpan": 1,
"textSize": {}
},
"options": {
"thresholds": {
"steps": [
{
"color": "#634CD9",
"value": null,
"type": "base"
}
]
},
"standardOptions": {}
}
},
{
"type": "pie",
"id": "e34a272e-6125-4afa-a2c1-80d7d9078673",
"layout": {
"h": 5,
"w": 18,
"x": 6,
"y": 0,
"i": "116a5607-5860-426e-a560-d3241da88b57",
"isResizable": true
},
"version": "3.0.0",
"datasourceCate": "prometheus",
"datasourceValue": 7,
"targets": [
{
"refId": "A",
"expr": "sum(delta(envoy_http_downstream_rq{envoy_clusterid=\"$envoy_clusterid\"}[3m])) by (response_code_class)",
"legend": ""
}
],
"transformations": [
{
"id": "organize",
"options": {}
}
],
"name": "请求成功率",
"maxPerRow": 4,
"custom": {
"calc": "lastNotNull",
"legengPosition": "right",
"detailName": "详情"
},
"options": {
"standardOptions": {
"util": "percentUnit",
"decimals": 0
}
}
},
{
"type": "timeseries",
"id": "a8917108-58a6-479a-8ec4-571f1b5a79c2",
"layout": {
"h": 5,
"w": 12,
"x": 0,
"y": 5,
"i": "9be66a1f-c0bb-47dc-a3c0-ad43b588789b",
"isResizable": true
},
"version": "3.0.0",
"datasourceCate": "prometheus",
"datasourceValue": 7,
"targets": [
{
"refId": "A",
"expr": "sum(delta(envoy_http_downstream_cx_rx_bytes_total{envoy_clusterid=\"$envoy_clusterid\"}[1m]))",
"legend": ""
}
],
"transformations": [
{
"id": "organize",
"options": {}
}
],
"name": "请求量(一分钟)",
"maxPerRow": 4,
"options": {
"tooltip": {
"mode": "all",
"sort": "none"
},
"legend": {
"displayMode": "list"
},
"standardOptions": {
"util": "bytesSI"
},
"thresholds": {
"steps": [
{
"color": "#634CD9",
"value": null,
"type": "base"
}
]
}
},
"custom": {
"drawStyle": "lines",
"lineInterpolation": "smooth",
"spanNulls": false,
"lineWidth": 1,
"fillOpacity": 0.5,
"gradientMode": "none",
"stack": "off",
"scaleDistribution": {
"type": "linear"
}
}
},
{
"type": "timeseries",
"id": "9062d707-d8a7-4a93-82e5-46f6059e8d70",
"layout": {
"h": 5,
"w": 12,
"x": 12,
"y": 5,
"i": "d36246b9-4a9c-4ab0-9171-c5ac330be0ca",
"isResizable": true
},
"version": "3.0.0",
"datasourceCate": "prometheus",
"datasourceValue": 7,
"targets": [
{
"refId": "A",
"expr": "sum(irate(envoy_http_downstream_rq{envoy_clusterid=\"$envoy_clusterid\"}[2m]))",
"legend": ""
}
],
"transformations": [
{
"id": "organize",
"options": {}
}
],
"name": "QPS",
"maxPerRow": 4,
"options": {
"tooltip": {
"mode": "all",
"sort": "none"
},
"legend": {
"displayMode": "list"
},
"standardOptions": {
"util": "none"
},
"thresholds": {
"steps": [
{
"color": "#634CD9",
"value": null,
"type": "base"
}
]
}
},
"custom": {
"drawStyle": "lines",
"lineInterpolation": "smooth",
"spanNulls": false,
"lineWidth": 1,
"fillOpacity": 0.5,
"gradientMode": "none",
"stack": "off",
"scaleDistribution": {
"type": "linear"
}
}
},
{
"type": "timeseries",
"id": "1b102bee-ccc9-49a0-a1d1-cc097bb6a987",
"layout": {
"h": 6,
"w": 12,
"x": 0,
"y": 10,
"i": "1b102bee-ccc9-49a0-a1d1-cc097bb6a987",
"isResizable": true
},
"version": "3.0.0",
"datasourceCate": "prometheus",
"datasourceValue": 7,
"targets": [
{
"refId": "A",
"expr": "sum(rate(envoy_http_downstream_rq_time_sum{envoy_clusterid=\"$envoy_clusterid\"}[10m])) / sum(rate(envoy_http_downstream_rq_time_count{envoy_clusterid=\"$envoy_clusterid\"}[10m]))",
"legend": ""
}
],
"transformations": [
{
"id": "organize",
"options": {}
}
],
"name": "平均延迟",
"maxPerRow": 4,
"options": {
"tooltip": {
"mode": "all",
"sort": "none"
},
"legend": {
"displayMode": "list"
},
"standardOptions": {
"util": "milliseconds"
},
"thresholds": {
"steps": [
{
"color": "#634CD9",
"value": null,
"type": "base"
}
]
}
},
"custom": {
"drawStyle": "lines",
"lineInterpolation": "smooth",
"spanNulls": false,
"lineWidth": 1,
"fillOpacity": 0.5,
"gradientMode": "none",
"stack": "off",
"scaleDistribution": {
"type": "linear"
}
}
},
{
"type": "timeseries",
"id": "b432fc11-2f9d-4b72-826b-6ca787401859",
"layout": {
"h": 6,
"w": 12,
"x": 12,
"y": 10,
"i": "ea4c1073-07d3-4adc-a4d3-4812cc55ad7c",
"isResizable": true
},
"version": "3.0.0",
"datasourceCate": "prometheus",
"datasourceValue": 7,
"targets": [
{
"refId": "A",
"expr": "histogram_quantile(0.95, sum(rate(envoy_http_downstream_rq_time_bucket{envoy_clusterid=\"$envoy_clusterid\"}[10m])) by (le, service))",
"legend": ""
}
],
"transformations": [
{
"id": "organize",
"options": {}
}
],
"name": "P95",
"maxPerRow": 4,
"options": {
"tooltip": {
"mode": "all",
"sort": "none"
},
"legend": {
"displayMode": "list"
},
"standardOptions": {
"util": "milliseconds"
},
"thresholds": {
"steps": [
{
"color": "#634CD9",
"value": null,
"type": "base"
}
]
}
},
"custom": {
"drawStyle": "lines",
"lineInterpolation": "smooth",
"spanNulls": false,
"lineWidth": 1,
"fillOpacity": 0.5,
"gradientMode": "none",
"stack": "off",
"scaleDistribution": {
"type": "linear"
}
}
},
{
"type": "barGauge",
"id": "c3f64cfd-adb2-4316-bb84-55f88ed513a3",
"layout": {
"h": 6,
"w": 24,
"x": 0,
"y": 16,
"i": "807c34f9-bd61-4da3-ad88-41bb3e045605",
"isResizable": true
},
"version": "3.0.0",
"datasourceCate": "prometheus",
"datasourceValue": 7,
"targets": [
{
"refId": "A",
"expr": "label_replace(label_replace(topk(10, sum(delta(envoy_cluster_upstream_rq_total{envoy_clusterid=\"$envoy_clusterid\", cluster_name=~\"outbound_([0-9]+)_(.*)_(.*).svc.cluster.local$\", cluster_name!~\".*waf-proxy.static\", cluster_name!~\"outbound_([0-9]+)_(.*)_kubernetes.default.svc.cluster.local\", cluster_name!~\"outbound_([0-9]+)_(.*)_(.*).kube-system.svc.cluster.local\", cluster_name!~\"outbound_([0-9]+)_(.*)_(.*).arms-prom.svc.cluster.local\"}[1m])) by (cluster_name)), \"service_name\", \"$3\", \"cluster_name\", \"outbound_([0-9]+)_(.*)_(.*).svc.cluster.local$\"), \"port\", \"$1\", \"cluster_name\", \"outbound_([0-9]+)_(.*)_(.*).svc.cluster.local$\")",
"legend": "{{service_name}}:{{port}}"
}
],
"transformations": [
{
"id": "organize",
"options": {}
}
],
"name": "Top Service Request",
"maxPerRow": 4,
"custom": {
"calc": "lastNotNull",
"baseColor": "#9470FF",
"serieWidth": 40,
"sortOrder": "desc"
},
"options": {
"standardOptions": {}
}
},
{
"type": "timeseries",
"id": "8df57678-ff19-4b63-b768-4dad3f12222b",
"layout": {
"h": 5,
"w": 24,
"x": 0,
"y": 22,
"i": "44f413ba-3262-4ccf-a4b1-c1165bafaaff",
"isResizable": true
},
"version": "3.0.0",
"datasourceCate": "prometheus",
"datasourceValue": 7,
"targets": [
{
"refId": "A",
"expr": "label_replace(label_replace(avg(delta(envoy_cluster_upstream_rq_time_sum{envoy_clusterid=\"$envoy_clusterid\", cluster_name=~\"outbound_([0-9]+)_(.*)_(.*)$\"}[3m])) by (cluster_name) / avg(delta(envoy_cluster_upstream_rq_time_count{envoy_clusterid=\"$envoy_clusterid\", cluster_name=~\"outbound_([0-9]+)_(.*)_(.*)$\"}[1m])) by (cluster_name), \"service_name\", \"$3\", \"cluster_name\", \"outbound_([0-9]+)_(.*)_(.*)$\"), \"port\", \"$1\", \"cluster_name\", \"outbound_([0-9]+)_(.*)_(.*)$\")",
"legend": "{{service_name}}:{{port}}"
}
],
"transformations": [
{
"id": "organize",
"options": {}
}
],
"name": "Top Service RT",
"maxPerRow": 4,
"options": {
"tooltip": {
"mode": "all",
"sort": "none"
},
"legend": {
"displayMode": "hidden"
},
"standardOptions": {
"util": "milliseconds"
},
"thresholds": {
"steps": [
{
"color": "#634CD9",
"value": null,
"type": "base"
}
]
}
},
"custom": {
"drawStyle": "lines",
"lineInterpolation": "smooth",
"spanNulls": false,
"lineWidth": 1,
"fillOpacity": 0.5,
"gradientMode": "none",
"stack": "off",
"scaleDistribution": {
"type": "linear"
}
}
}
],
"version": "3.0.0"
}
}

View File

@@ -17,25 +17,62 @@
],
"panels": [
{
"type": "hexbin",
"custom": {
"calc": "lastNotNull",
"colorRange": [
"thresholds"
],
"detailUrl": "/dashboards/linux-host-by-categraf?ident=${__field.labels.ident}",
"textMode": "valueAndName"
},
"datasourceCate": "prometheus",
"datasourceValue": "${prom}",
"id": "21b8b3ab-26aa-47cb-b814-f310f2d143aa",
"layout": {
"h": 5,
"i": "21b8b3ab-26aa-47cb-b814-f310f2d143aa",
"isResizable": true,
"w": 12,
"x": 0,
"y": 0,
"i": "21b8b3ab-26aa-47cb-b814-f310f2d143aa",
"isResizable": true
"y": 0
},
"maxPerRow": 4,
"name": "CPU利用率",
"options": {
"standardOptions": {
"util": "percent"
},
"thresholds": {
"steps": [
{
"color": "#ef3c3c",
"type": "",
"value": 95
},
{
"color": "#ff656b",
"type": "",
"value": 85
},
{
"color": "#ffae39",
"type": "",
"value": 75
},
{
"color": "#2c9d3d",
"type": "base",
"value": null
}
]
}
},
"version": "3.0.0",
"datasourceCate": "prometheus",
"datasourceValue": "${prom}",
"targets": [
{
"refId": "A",
"expr": "cpu_usage_active{cpu=\"cpu-total\", ident=~\"$ident\"}",
"instant": true,
"legend": "{{ident}}",
"instant": true
"refId": "A"
}
],
"transformations": [
@@ -44,66 +81,66 @@
"options": {}
}
],
"name": "CPU利用率",
"maxPerRow": 4,
"type": "hexbin",
"version": "3.0.0"
},
{
"custom": {
"textMode": "valueAndName",
"calc": "lastNotNull",
"colorRange": [
"thresholds"
],
"detailUrl": "/dashboards/linux-host-by-categraf?ident=${__field.labels.ident}"
"detailUrl": "/dashboards/linux-host-by-categraf?ident=${__field.labels.ident}",
"textMode": "valueAndName"
},
"options": {
"thresholds": {
"steps": [
{
"color": "#ef3c3c",
"value": 95,
"type": ""
},
{
"color": "#ff656b",
"value": 85,
"type": ""
},
{
"color": "#ffae39",
"value": 75,
"type": ""
},
{
"color": "#2c9d3d",
"value": null,
"type": "base"
}
]
},
"standardOptions": {
"util": "percent"
}
}
},
{
"type": "hexbin",
"datasourceCate": "prometheus",
"datasourceValue": "${prom}",
"id": "86d4a502-21f7-4981-9b38-ed8e696b6f49",
"layout": {
"h": 5,
"i": "872b2040-c5b0-43fe-92c7-e37cb77edffc",
"isResizable": true,
"w": 12,
"x": 12,
"y": 0,
"i": "872b2040-c5b0-43fe-92c7-e37cb77edffc",
"isResizable": true
"y": 0
},
"maxPerRow": 4,
"name": "内存利用率",
"options": {
"standardOptions": {
"util": "percent"
},
"thresholds": {
"steps": [
{
"color": "#ef3c3c",
"type": "",
"value": 95
},
{
"color": "#ff656b",
"type": "",
"value": 85
},
{
"color": "#ffae39",
"type": "",
"value": 75
},
{
"color": "#2c9d3d",
"type": "base",
"value": null
}
]
}
},
"version": "3.0.0",
"datasourceCate": "prometheus",
"datasourceValue": "${prom}",
"targets": [
{
"refId": "A",
"expr": "mem_used_percent{ident=~\"$ident\"}",
"instant": true,
"legend": "{{ident}}",
"instant": true
"refId": "A"
}
],
"transformations": [
@@ -112,56 +149,19 @@
"options": {}
}
],
"name": "内存利用率",
"maxPerRow": 4,
"custom": {
"textMode": "valueAndName",
"calc": "lastNotNull",
"colorRange": [
"thresholds"
],
"detailUrl": "/dashboards/linux-host-by-categraf?ident=${__field.labels.ident}"
},
"options": {
"thresholds": {
"steps": [
{
"color": "#ef3c3c",
"value": 95,
"type": ""
},
{
"color": "#ff656b",
"value": 85,
"type": ""
},
{
"color": "#ffae39",
"value": 75,
"type": ""
},
{
"color": "#2c9d3d",
"value": null,
"type": "base"
}
]
},
"standardOptions": {
"util": "percent"
}
}
"type": "hexbin",
"version": "3.0.0"
},
{
"type": "table",
"id": "77bf513a-8504-4d33-9efe-75aaf9abc9e4",
"layout": {
"h": 11,
"i": "77bf513a-8504-4d33-9efe-75aaf9abc9e4",
"isResizable": true,
"w": 24,
"x": 0,
"y": 5,
"i": "77bf513a-8504-4d33-9efe-75aaf9abc9e4",
"isResizable": true
"y": 5
},
"version": "3.0.0",
"datasourceCate": "prometheus",
@@ -208,10 +208,11 @@
"aggrDimension": "ident",
"sortColumn": "ident",
"sortOrder": "ascend",
"linkMode": "appendLinkColumn",
"links": [
{
"title": "详情",
"url": "/dashboards/linux-host-by-categraf?ident=${__field.labels.ident}"
"url": "/dashboards-built-in/detail?__built-in-cate=Linux&__built-in-name=Linux%20Host%20by%20Categraf&${__field.labels.ident}&prom=1"
}
]
},
@@ -221,7 +222,8 @@
"overrides": [
{
"matcher": {
"value": "A"
"value": "A",
"id": "byFrameRefID"
},
"properties": {
"standardOptions": {
@@ -260,7 +262,8 @@
},
{
"matcher": {
"value": "B"
"value": "B",
"id": "byFrameRefID"
},
"properties": {
"standardOptions": {
@@ -300,7 +303,8 @@
},
{
"matcher": {
"value": "C"
"value": "C",
"id": "byFrameRefID"
},
"properties": {
"standardOptions": {
@@ -313,7 +317,8 @@
},
{
"matcher": {
"value": "D"
"value": "D",
"id": "byFrameRefID"
},
"properties": {
"standardOptions": {
@@ -322,22 +327,22 @@
},
"valueMappings": [
{
"type": "range",
"match": {
"to": 90
},
"result": {
"color": "#2c9d3d"
},
"match": {
"to": 90
}
"type": "range"
},
{
"type": "range",
"match": {
"from": 90
},
"result": {
"color": "#ff656b"
},
"match": {
"from": 90
}
"type": "range"
}
]
},

View File

@@ -1,334 +0,0 @@
{
"name": "中间件业务-Seata集群-公共业务服务-服务看板",
"tags": "",
"ident": "",
"configs": {
"version": "2.0.0",
"links": [],
"var": [
{
"type": "query",
"name": "instance",
"definition": "label_values(seata_transaction,instance)",
"allValue": null,
"allOption": false,
"multi": false,
"reg": ""
},
{
"type": "query",
"name": "group",
"definition": "label_values(seata_transaction,group)",
"allValue": null,
"allOption": true,
"multi": true,
"reg": ""
}
],
"panels": [
{
"type": "timeseries",
"id": "5a0db458-1fc7-4089-9265-d4bc74d015a4",
"layout": {
"h": 7,
"w": 8,
"x": 0,
"y": 0,
"i": "5a0db458-1fc7-4089-9265-d4bc74d015a4",
"isResizable": true
},
"version": "2.0.0",
"datasourceCate": "prometheus",
"targets": [
{
"refId": "A",
"expr": "sum(seata_transaction{instance=\"$instance\",group=~\"$group\",meter=\"summary\",statistic=\"count\",status=~\"committed|rollbacked\"}) by (status)",
"legend": ""
}
],
"name": "正常事务",
"options": {
"tooltip": {
"mode": "all",
"sort": "none"
},
"legend": {
"displayMode": "hidden"
},
"standardOptions": {
"util": "none"
},
"thresholds": {
"steps": [
{
"color": "#634CD9",
"value": null,
"type": "base"
}
]
}
},
"custom": {
"drawStyle": "lines",
"lineInterpolation": "smooth",
"spanNulls": false,
"lineWidth": 1,
"fillOpacity": 0.5,
"gradientMode": "none",
"stack": "off",
"scaleDistribution": {
"type": "linear"
}
}
},
{
"type": "timeseries",
"id": "ae6d99b2-2541-4093-838f-17dc358490e6",
"layout": {
"h": 7,
"w": 8,
"x": 8,
"y": 0,
"i": "604eb46d-b669-4ad6-890b-e7a45ef0ccec",
"isResizable": true
},
"version": "2.0.0",
"datasourceCate": "prometheus",
"targets": [
{
"refId": "A",
"expr": "sum(seata_transaction{instance=\"$instance\",group=~\"$group\",meter=\"summary\",statistic=\"count\",status=~\"unretry|timeout\"}) by (status)",
"legend": ""
}
],
"name": "异常事务",
"options": {
"tooltip": {
"mode": "all",
"sort": "none"
},
"legend": {
"displayMode": "hidden"
},
"standardOptions": {
"util": "none"
},
"thresholds": {
"steps": [
{
"color": "#634CD9",
"value": null,
"type": "base"
}
]
}
},
"custom": {
"drawStyle": "lines",
"lineInterpolation": "smooth",
"spanNulls": false,
"lineWidth": 1,
"fillOpacity": 0.5,
"gradientMode": "none",
"stack": "off",
"scaleDistribution": {
"type": "linear"
}
}
},
{
"type": "timeseries",
"id": "c0341b0a-5e6e-4b7b-8916-003528e64ea4",
"layout": {
"h": 7,
"w": 8,
"x": 16,
"y": 0,
"i": "f835a637-11e1-4d9c-91ec-6bbcd874156b",
"isResizable": true
},
"version": "2.0.0",
"datasourceCate": "prometheus",
"targets": [
{
"refId": "A",
"expr": "avg(seata_transaction{instance=\"$instance\",group=~\"$group\",meter=\"timer\",statistic=\"average\"}) by (status)",
"legend": ""
}
],
"name": "事务耗时(含业务时间)",
"options": {
"tooltip": {
"mode": "all",
"sort": "none"
},
"legend": {
"displayMode": "hidden"
},
"standardOptions": {
"util": "none"
},
"thresholds": {
"steps": [
{
"color": "#634CD9",
"value": null,
"type": "base"
}
]
}
},
"custom": {
"drawStyle": "lines",
"lineInterpolation": "smooth",
"spanNulls": false,
"lineWidth": 1,
"fillOpacity": 0.5,
"gradientMode": "none",
"stack": "off",
"scaleDistribution": {
"type": "linear"
}
}
},
{
"type": "timeseries",
"id": "0ed8fd7a-baa7-4b04-a003-d7fe0c26db11",
"layout": {
"h": 7,
"w": 8,
"x": 0,
"y": 7,
"i": "80f0ee2b-8706-43b4-a24a-ca8c7ce334f9",
"isResizable": true
},
"version": "2.0.0",
"datasourceCate": "prometheus",
"targets": [
{
"refId": "A",
"expr": "sum(seata_transaction{instance=\"$instance\",group=~\"$group\",meter=\"summary\",statistic=\"tps\"}) by (status)",
"legend": "{{status}}"
}
],
"name": "事务TPS(按状态)",
"options": {
"tooltip": {
"mode": "all",
"sort": "none"
},
"legend": {
"displayMode": "hidden"
},
"standardOptions": {
"util": "none"
},
"thresholds": {
"steps": [
{
"color": "#634CD9",
"value": null,
"type": "base"
}
]
}
},
"custom": {
"drawStyle": "lines",
"lineInterpolation": "smooth",
"spanNulls": false,
"lineWidth": 1,
"fillOpacity": 0.5,
"gradientMode": "none",
"stack": "off",
"scaleDistribution": {
"type": "linear"
}
}
},
{
"type": "timeseries",
"id": "26f4ddbb-ddfd-4cbc-a71e-2530b6d59465",
"layout": {
"h": 7,
"w": 8,
"x": 8,
"y": 7,
"i": "869a8477-04ca-48c0-8c87-bd6859d61675",
"isResizable": true
},
"version": "2.0.0",
"datasourceCate": "prometheus",
"targets": [
{
"refId": "A",
"expr": "sum(rate(seata_transaction{instance=\"$instance\",group=~\"$group\",meter=\"counter\",status=~\"committed|rollbacked\"}[1m])) by (instance)",
"legend": "{{instance}}{{pod}}"
}
],
"name": "事务TPS(按容器)",
"options": {
"tooltip": {
"mode": "all",
"sort": "none"
},
"legend": {
"displayMode": "hidden"
},
"standardOptions": {
"util": "none"
},
"thresholds": {
"steps": [
{
"color": "#634CD9",
"value": null,
"type": "base"
}
]
}
},
"custom": {
"drawStyle": "lines",
"lineInterpolation": "smooth",
"spanNulls": false,
"lineWidth": 1,
"fillOpacity": 0.5,
"gradientMode": "none",
"stack": "off",
"scaleDistribution": {
"type": "linear"
}
}
},
{
"type": "pie",
"id": "240abb70-e5b9-43e9-b691-c14f4be3b92a",
"layout": {
"h": 7,
"w": 8,
"x": 16,
"y": 7,
"i": "240abb70-e5b9-43e9-b691-c14f4be3b92a",
"isResizable": true
},
"version": "2.0.0",
"datasourceCate": "prometheus",
"targets": [
{
"refId": "A",
"expr": "sum(seata_transaction{instance=\"$instance\",group=~\"$group\",meter=\"counter\"}) by (status)",
"legend": "{{status}}"
}
],
"name": "事务总量统计",
"custom": {
"calc": "lastNotNull",
"legengPosition": "right",
"donut": false,
"labelWithName": true
}
}
]
}
}

View File

@@ -1290,10 +1290,9 @@
"name": "ident",
"type": "query",
"datasource": {
"cate": "prometheus",
"value": "${prom}"
"cate": "prometheus"
},
"definition": "label_values(system_load1{disk_used_percent{device=~\".+:\"},ident)",
"definition": "label_values(disk_used_percent{device=~\".+:\"},ident)",
"multi": true,
"allOption": true
}

View File

@@ -102,7 +102,7 @@ func (w *NotifyConfigCacheType) syncNotifyConfigs() error {
return err
}
cval = tplx.ReplaceMacroVariables(models.SMTP, cval, userVariableMap)
cval = tplx.ReplaceTemplateUseText(models.SMTP, cval, userVariableMap)
if strings.TrimSpace(cval) != "" {
err = toml.Unmarshal([]byte(cval), &w.smtp)

View File

@@ -17,53 +17,53 @@ import (
)
type AlertCurEvent struct {
Id int64 `json:"id" gorm:"primaryKey"`
Cate string `json:"cate"`
Cluster string `json:"cluster"`
DatasourceId int64 `json:"datasource_id"`
GroupId int64 `json:"group_id"` // busi group id
GroupName string `json:"group_name"` // busi group name
Hash string `json:"hash"` // rule_id + vector_key
RuleId int64 `json:"rule_id"`
RuleName string `json:"rule_name"`
RuleNote string `json:"rule_note"`
RuleProd string `json:"rule_prod"`
RuleAlgo string `json:"rule_algo"`
Severity int `json:"severity"`
PromForDuration int `json:"prom_for_duration"`
PromQl string `json:"prom_ql"`
RuleConfig string `json:"-" gorm:"rule_config"` // rule config
RuleConfigJson interface{} `json:"rule_config" gorm:"-"` // rule config for fe
PromEvalInterval int `json:"prom_eval_interval"`
Callbacks string `json:"-"` // for db
CallbacksJSON []string `json:"callbacks" gorm:"-"` // for fe
RunbookUrl string `json:"runbook_url"`
NotifyRecovered int `json:"notify_recovered"`
NotifyChannels string `json:"-"` // for db
NotifyChannelsJSON []string `json:"notify_channels" gorm:"-"` // for fe
NotifyGroups string `json:"-"` // for db
NotifyGroupsJSON []string `json:"notify_groups" gorm:"-"` // for fe
NotifyGroupsObj []*UserGroup `json:"notify_groups_obj" gorm:"-"` // for fe
TargetIdent string `json:"target_ident"`
TargetNote string `json:"target_note"`
TriggerTime int64 `json:"trigger_time"`
TriggerValue string `json:"trigger_value"`
Tags string `json:"-"` // for db
TagsJSON []string `json:"tags" gorm:"-"` // for fe
TagsMap map[string]string `json:"tags_map" gorm:"-"` // for internal usage
Annotations string `json:"-"` //
AnnotationsJSON map[string]string `json:"annotations" gorm:"-"` // for fe
IsRecovered bool `json:"is_recovered" gorm:"-"` // for notify.py
NotifyUsersObj []*User `json:"notify_users_obj" gorm:"-"` // for notify.py
LastEvalTime int64 `json:"last_eval_time" gorm:"-"` // for notify.py 上次计算的时间
LastEscalationNotifyTime int64 `json:"last_escalation_notify_time" gorm:"-"`
LastSentTime int64 `json:"last_sent_time" gorm:"-"` // 上次发送时间
NotifyCurNumber int `json:"notify_cur_number"` // notify: current number
FirstTriggerTime int64 `json:"first_trigger_time"` // 连续告警的首次告警时间
ExtraConfig interface{} `json:"extra_config" gorm:"-"`
Status int `json:"status" gorm:"-"`
Claimant string `json:"claimant" gorm:"-"`
SubRuleId int64 `json:"sub_rule_id" gorm:"-"`
Id int64 `json:"id" gorm:"primaryKey"`
Cate string `json:"cate"`
Cluster string `json:"cluster"`
DatasourceId int64 `json:"datasource_id"`
GroupId int64 `json:"group_id"` // busi group id
GroupName string `json:"group_name"` // busi group name
Hash string `json:"hash"` // rule_id + vector_key
RuleId int64 `json:"rule_id"`
RuleName string `json:"rule_name"`
RuleNote string `json:"rule_note"`
RuleProd string `json:"rule_prod"`
RuleAlgo string `json:"rule_algo"`
Severity int `json:"severity"`
PromForDuration int `json:"prom_for_duration"`
PromQl string `json:"prom_ql"`
RuleConfig string `json:"-" gorm:"rule_config"` // rule config
RuleConfigJson interface{} `json:"rule_config" gorm:"-"` // rule config for fe
PromEvalInterval int `json:"prom_eval_interval"`
Callbacks string `json:"-"` // for db
CallbacksJSON []string `json:"callbacks" gorm:"-"` // for fe
RunbookUrl string `json:"runbook_url"`
NotifyRecovered int `json:"notify_recovered"`
NotifyChannels string `json:"-"` // for db
NotifyChannelsJSON []string `json:"notify_channels" gorm:"-"` // for fe
NotifyGroups string `json:"-"` // for db
NotifyGroupsJSON []string `json:"notify_groups" gorm:"-"` // for fe
NotifyGroupsObj []*UserGroup `json:"notify_groups_obj" gorm:"-"` // for fe
TargetIdent string `json:"target_ident"`
TargetNote string `json:"target_note"`
TriggerTime int64 `json:"trigger_time"`
TriggerValue string `json:"trigger_value"`
Tags string `json:"-"` // for db
TagsJSON []string `json:"tags" gorm:"-"` // for fe
TagsMap map[string]string `json:"tags_map" gorm:"-"` // for internal usage
Annotations string `json:"-"` //
AnnotationsJSON map[string]string `json:"annotations" gorm:"-"` // for fe
IsRecovered bool `json:"is_recovered" gorm:"-"` // for notify.py
NotifyUsersObj []*User `json:"notify_users_obj" gorm:"-"` // for notify.py
LastEvalTime int64 `json:"last_eval_time" gorm:"-"` // for notify.py 上次计算的时间
LastSentTime int64 `json:"last_sent_time" gorm:"-"` // 上次发送时间
NotifyCurNumber int `json:"notify_cur_number"` // notify: current number
FirstTriggerTime int64 `json:"first_trigger_time"` // 连续告警的首次告警时间
ExtraConfig interface{} `json:"extra_config" gorm:"-"`
Status int `json:"status" gorm:"-"`
Claimant string `json:"claimant" gorm:"-"`
SubRuleId int64 `json:"sub_rule_id" gorm:"-"`
ExtraInfo []string `json:"extra_info" gorm:"-"`
}
func (e *AlertCurEvent) TableName() string {

View File

@@ -85,6 +85,16 @@ func InsertPermPoints(db *gorm.DB) {
Operation: "/log/index-patterns",
})
ops = append(ops, models.RoleOperation{
RoleName: "Standard",
Operation: "/help/variable-configs",
})
ops = append(ops, models.RoleOperation{
RoleName: "Admin",
Operation: "/permissions",
})
for _, op := range ops {
exists, err := models.Exists(db.Model(&models.RoleOperation{}).Where("operation = ? and role_name = ?", op.Operation, op.RoleName))
if err != nil {

View File

@@ -567,9 +567,10 @@ func (u *User) UserGroups(ctx *ctx.Context, limit int, query string) ([]UserGrou
return lst, err
}
var user *User
if len(lst) == 0 && len(query) > 0 {
// 隐藏功能一般人不告诉哈哈。query可能是给的用户名所以上面的sql没有查到当做user来查一下试试
user, err := UserGetByUsername(ctx, query)
user, err = UserGetByUsername(ctx, query)
if user == nil {
return lst, err
}

View File

@@ -2,6 +2,7 @@ package aop
import (
"bytes"
"compress/gzip"
"fmt"
"io"
"net/http"
@@ -40,7 +41,8 @@ type LoggerConfig struct {
// Output is a writer where logs are written.
// Optional. Default value is gin.DefaultWriter.
Output io.Writer
Output io.Writer
PrintBody bool
// SkipPaths is a url path array which logs are not written.
// Optional.
@@ -177,8 +179,13 @@ func ErrorLoggerT(typ gin.ErrorType) gin.HandlerFunc {
// Logger instances a Logger middleware that will write the logs to gin.DefaultWriter.
// By default gin.DefaultWriter = os.Stdout.
func Logger() gin.HandlerFunc {
return LoggerWithConfig(LoggerConfig{})
func Logger(conf ...LoggerConfig) gin.HandlerFunc {
var configuration LoggerConfig
if len(conf) > 0 {
configuration = conf[0]
}
return LoggerWithConfig(configuration)
}
// LoggerWithFormatter instance a Logger middleware with the specified log format function.
@@ -197,6 +204,21 @@ func LoggerWithWriter(out io.Writer, notlogged ...string) gin.HandlerFunc {
})
}
type CustomResponseWriter struct {
gin.ResponseWriter
body *bytes.Buffer
}
func (w CustomResponseWriter) Write(data []byte) (int, error) {
w.body.Write(data)
return w.ResponseWriter.Write(data)
}
func (w CustomResponseWriter) WriteString(s string) (int, error) {
w.body.WriteString(s)
return w.ResponseWriter.WriteString(s)
}
// LoggerWithConfig instance a Logger middleware with config.
func LoggerWithConfig(conf LoggerConfig) gin.HandlerFunc {
formatter := conf.Formatter
@@ -234,18 +256,24 @@ func LoggerWithConfig(conf LoggerConfig) gin.HandlerFunc {
path := c.Request.URL.Path
raw := c.Request.URL.RawQuery
// var (
// rdr1 io.ReadCloser
// rdr2 io.ReadCloser
// )
var (
rdr1 io.ReadCloser
rdr2 io.ReadCloser
)
// if c.Request.Method != "GET" {
// buf, _ := ioutil.ReadAll(c.Request.Body)
// rdr1 = ioutil.NopCloser(bytes.NewBuffer(buf))
// rdr2 = ioutil.NopCloser(bytes.NewBuffer(buf))
bodyWriter := &CustomResponseWriter{
ResponseWriter: c.Writer,
body: bytes.NewBuffer(nil),
}
c.Writer = bodyWriter
// c.Request.Body = rdr2
// }
if conf.PrintBody {
buf, _ := io.ReadAll(c.Request.Body)
rdr1 = io.NopCloser(bytes.NewBuffer(buf))
rdr2 = io.NopCloser(bytes.NewBuffer(buf))
c.Request.Body = rdr2
}
// Process request
c.Next()
@@ -277,18 +305,36 @@ func LoggerWithConfig(conf LoggerConfig) gin.HandlerFunc {
// fmt.Fprint(out, formatter(param))
logger.Info(formatter(param))
// if c.Request.Method != "GET" {
// logger.Debug(readBody(rdr1))
// }
if conf.PrintBody {
respBody := readBody(bytes.NewReader(bodyWriter.body.Bytes()), c.Writer.Header().Get("Content-Encoding"))
reqBody := readBody(rdr1, c.Request.Header.Get("Content-Encoding"))
logger.Debugf("path:%s req body:%s resp:%s", path, reqBody, respBody)
}
}
}
}
func readBody(reader io.Reader) string {
buf := new(bytes.Buffer)
buf.ReadFrom(reader)
func readBody(reader io.Reader, encoding string) string {
var bodyBytes []byte
var err error
s := buf.String()
return s
if encoding == "gzip" {
gzipReader, err := gzip.NewReader(reader)
if err != nil {
return fmt.Sprintf("failed to create gzip reader: %v", err)
}
defer gzipReader.Close()
bodyBytes, err = io.ReadAll(gzipReader)
if err != nil {
return fmt.Sprintf("failed to read gzip response body: %v", err)
}
} else {
bodyBytes, err = io.ReadAll(reader)
if err != nil {
return fmt.Sprintf("failed to read response body: %v", err)
}
}
return string(bodyBytes)
}

View File

@@ -24,6 +24,7 @@ type Config struct {
KeyFile string
PProf bool
PrintAccessLog bool
PrintBody bool
ExposeMetrics bool
ShutdownTimeout int
MaxContentLength int64
@@ -72,7 +73,7 @@ type JWTAuth struct {
func GinEngine(mode string, cfg Config) *gin.Engine {
gin.SetMode(mode)
loggerMid := aop.Logger()
loggerMid := aop.Logger(aop.LoggerConfig{PrintBody: cfg.PrintBody})
recoveryMid := aop.Recovery()
if strings.ToLower(mode) == "release" {

View File

@@ -6,6 +6,7 @@ import (
"net/url"
"regexp"
"strings"
templateT "text/template"
"github.com/toolkits/pkg/logger"
)
@@ -37,7 +38,7 @@ var TemplateFuncMap = template.FuncMap{
"formatDecimal": FormatDecimal,
}
// ReplaceMacroVariables replaces variables in a template string with values.
// ReplaceTemplateUseHtml replaces variables in a template string with values.
//
// It accepts the following parameters:
//
@@ -45,14 +46,14 @@ var TemplateFuncMap = template.FuncMap{
//
// - templateText: The template string containing variables to replace
//
// - macroValue: A struct containing fields to replace the variables
// - templateData: A struct containing fields to replace the variables
//
// It parses the templateText into a template using template.New and template.Parse.
//
// It executes the parsed template with macroValue as the data, writing the result
// It executes the parsed template with templateData as the data, writing the result
// to a bytes.Buffer.
//
// Any {{.Field}} variables in templateText are replaced with values from macroValue.
// Any {{.Field}} variables in templateText are replaced with values from templateData.
//
// If there are any errors parsing or executing the template, they are logged and
// the original templateText is returned.
@@ -67,17 +68,31 @@ var TemplateFuncMap = template.FuncMap{
//
// data := Data{"John"}
//
// output := ReplaceMacroVariables("mytpl", "Hello {{.Name}}!", data)
func ReplaceMacroVariables(name string, templateText string, macroValue any) string {
// output := ReplaceTemplateUseHtml("mytpl", "Hello {{.Name}}!", data)
func ReplaceTemplateUseHtml(name string, templateText string, templateData any) string {
tpl, err := template.New(name).Parse(templateText)
if err != nil {
logger.Warningf("parse config error: %v", err)
return templateText
}
var body bytes.Buffer
if err := tpl.Execute(&body, macroValue); err != nil {
if err := tpl.Execute(&body, templateData); err != nil {
logger.Warningf("execute config error: %v", err)
return templateText
}
return body.String()
}
func ReplaceTemplateUseText(name string, templateText string, templateData any) string {
tpl, err := templateT.New(name).Parse(templateText)
if err != nil {
logger.Warningf("text parse config error: %v", err)
return templateText
}
var body bytes.Buffer
if err := tpl.Execute(&body, templateData); err != nil {
logger.Warningf("text execute config error: %v", err)
return templateText
}
return body.String()
}