diff --git a/build/conf/archive_mysql_tool.json b/build/conf/archive_mysql_tool.json
index 5931fffae..bf6090877 100644
--- a/build/conf/archive_mysql_tool.json
+++ b/build/conf/archive_mysql_tool.json
@@ -6,7 +6,7 @@
     "user": "{{MONITOR_ARCHIVE_MYSQL_USER}}",
     "password": "{{MONITOR_ARCHIVE_MYSQL_PWD}}",
     "database_prefix": "prometheus_archive_",
-    "max_open": 100,
+    "max_open": 150,
     "max_idle": 10,
     "timeout": 60
   },
@@ -33,7 +33,9 @@
   },
   "trans": {
     "max_unit_speed": 5,
-    "five_min_start_day": 90
+    "five_min_start_day": 90,
+    "concurrent_insert_num": 100,
+    "retry_wait_second": 60
   },
   "http": {
     "enable": true,
diff --git a/monitor-agent/agent_manager/funcs/manager.go b/monitor-agent/agent_manager/funcs/manager.go
index 2fede9997..71bc0fda9 100644
--- a/monitor-agent/agent_manager/funcs/manager.go
+++ b/monitor-agent/agent_manager/funcs/manager.go
@@ -183,6 +183,7 @@ func LoadDeployProcess()  {
 						log.Printf("process start error : %v \n", err)
 					} else {
 						GlobalProcessMap[p.Guid] = &p
+						deployGuidStatus[p.Guid] = p.Status
 					}
 				}
 			}
diff --git a/monitor-agent/archive_mysql_tool/default.json b/monitor-agent/archive_mysql_tool/default.json
index aeeeee830..6ca5afa90 100644
--- a/monitor-agent/archive_mysql_tool/default.json
+++ b/monitor-agent/archive_mysql_tool/default.json
@@ -6,7 +6,7 @@
     "user": "root",
     "password": "wecube",
     "database_prefix": "prometheus_archive_",
-    "max_open": 100,
+    "max_open": 150,
     "max_idle": 10,
     "timeout": 60
   },
@@ -33,7 +33,9 @@
   },
   "trans": {
     "max_unit_speed": 5,
-    "five_min_start_day": 90
+    "five_min_start_day": 90,
+    "concurrent_insert_num": 100,
+    "retry_wait_second": 60
   },
   "http": {
     "enable": true,
diff --git a/monitor-agent/archive_mysql_tool/funcs/config.go b/monitor-agent/archive_mysql_tool/funcs/config.go
index f73c562cb..668d0083f 100644
--- a/monitor-agent/archive_mysql_tool/funcs/config.go
+++ b/monitor-agent/archive_mysql_tool/funcs/config.go
@@ -39,6 +39,8 @@ type MonitorConfig struct {
 type TransConfig struct {
 	MaxUnitSpeed  int  `json:"max_unit_speed"`
 	FiveMinStartDay int64 `json:"five_min_start_day"`
+	ConcurrentInsertNum  int  `json:"concurrent_insert_num"`
+	RetryWaitSecond  int  `json:"retry_wait_second"`
 }
 
 type HttpConfig struct {
diff --git a/monitor-agent/archive_mysql_tool/funcs/db.go b/monitor-agent/archive_mysql_tool/funcs/db.go
index 9a703fde4..f61f29195 100644
--- a/monitor-agent/archive_mysql_tool/funcs/db.go
+++ b/monitor-agent/archive_mysql_tool/funcs/db.go
@@ -17,6 +17,9 @@ var (
 	monitorMysqlEngine *xorm.Engine
 	databaseSelect string
 	hostIp string
+	maxUnitNum int
+	concurrentInsertNum int
+	retryWaitSecond int
 )
 
 func InitDbEngine(databaseName string) (err error) {
@@ -66,23 +69,49 @@ func InitMonitorDbEngine() (err error) {
 
 func insertMysql(rows []*ArchiveTable,tableName string) error {
 	var sqlList []string
+	var rowCountList []int
+	tmpCount := 0
 	sqlString := fmt.Sprintf("INSERT INTO %s VALUES ", tableName)
 	for i,v := range rows {
+		tmpCount += 1
 		sqlString += fmt.Sprintf("('%s','%s','%s',%d,%.3f,%.3f,%.3f,%.3f)", v.Endpoint, v.Metric, v.Tags, v.UnixTime, v.Avg, v.Min, v.Max, v.P95)
-		if (i+1)%100 == 0 || i == len(rows)-1 {
+		if (i+1)%concurrentInsertNum == 0 || i == len(rows)-1 {
+			rowCountList = append(rowCountList, tmpCount)
+			tmpCount = 0
 			sqlList = append(sqlList, sqlString)
 			sqlString = fmt.Sprintf("INSERT INTO %s VALUES ", tableName)
 		}else{
 			sqlString += ","
 		}
 	}
-	for _,v := range sqlList {
-		_,err := mysqlEngine.Exec(v)
-		if err != nil {
-			return err
+	gErrMessage := ""
+	for sqlIndex, v := range sqlList {
+		var tmpErr error
+		for i:=0;i<3;i++ {
+			_, err := mysqlEngine.Exec(v)
+			if err != nil {
+				tmpErr = err
+			} else {
+				tmpErr = nil
+				break
+			}
+			if i < 2 {
+				time.Sleep(time.Duration(retryWaitSecond) * time.Second)
+			}
+		}
+		if tmpErr != nil {
+			tmpErrorString := tmpErr.Error()
+			if len(tmpErrorString) > 200 {
+				tmpErrorString = tmpErrorString[:200]
+			}
+			gErrMessage += fmt.Sprintf("fail with rows length:%d error:%s \n", rowCountList[sqlIndex], tmpErrorString)
 		}
 	}
-	return nil
+	if gErrMessage == "" {
+		return nil
+	}else{
+		return fmt.Errorf(gErrMessage)
+	}
 }
 
 func createTable(start int64,isFiveArchive bool) (err error, tableName string) {
diff --git a/monitor-agent/archive_mysql_tool/funcs/job.go b/monitor-agent/archive_mysql_tool/funcs/job.go
index 5838ad481..caa5aef0d 100644
--- a/monitor-agent/archive_mysql_tool/funcs/job.go
+++ b/monitor-agent/archive_mysql_tool/funcs/job.go
@@ -3,6 +3,7 @@ package funcs
 import (
 	"log"
 	"sort"
+	"sync"
 	"time"
 	"fmt"
 )
@@ -10,6 +11,18 @@ import (
 var jobChannelList chan ArchiveActionList
 
 func StartCronJob()  {
+	concurrentInsertNum = 50
+	if Config().Trans.ConcurrentInsertNum > 0 {
+		concurrentInsertNum = Config().Trans.ConcurrentInsertNum
+	}
+	maxUnitNum = 5
+	if Config().Trans.MaxUnitSpeed > 0 {
+		maxUnitNum = Config().Trans.MaxUnitSpeed
+	}
+	retryWaitSecond = 60
+	if Config().Trans.RetryWaitSecond > 0 {
+		retryWaitSecond = Config().Trans.RetryWaitSecond
+	}
 	jobChannelList = make(chan ArchiveActionList, Config().Prometheus.MaxHttpOpen)
 	go consumeJob()
 	t,_ := time.Parse("2006-01-02 15:04:05 MST", fmt.Sprintf("%s 00:00:00 CST", time.Now().Format("2006-01-02")))
@@ -55,25 +68,15 @@ func CreateJob(dateString string)  {
 		log.Printf("try to create table:%s error:%v \n", tableName, err)
 		return
 	}
-	var unitPerJob int
 	unitCount := 0
-	for _,v := range MonitorObjList {
-		unitPerJob += len(v.Metrics)
-	}
-	unitPerJob = unitPerJob/Config().Prometheus.MaxHttpOpen
-	if unitPerJob > Config().Trans.MaxUnitSpeed {
-		unitPerJob = Config().Trans.MaxUnitSpeed
-	}
-	if unitPerJob == 0 {
-		unitPerJob = 1
-	}
+	actionParamObjLength := maxUnitNum*Config().Prometheus.MaxHttpOpen
 	var actionParamList []*ArchiveActionList
 	var tmpActionParamObjList []*ArchiveActionParamObj
 	for _,v := range MonitorObjList {
 		for _,vv := range v.Metrics {
 			unitCount++
 			tmpActionParamObjList = append(tmpActionParamObjList, &ArchiveActionParamObj{Endpoint:v.Endpoint, Metric:vv.Metric, PromQl:vv.PromQl, TableName:tableName, Start:start, End:end})
-			if unitCount == unitPerJob {
+			if unitCount == actionParamObjLength {
 				tmpArchiveActionList := ArchiveActionList{}
 				for _,vvv := range tmpActionParamObjList {
 					tmpArchiveActionList = append(tmpArchiveActionList, vvv)
@@ -84,6 +87,13 @@ func CreateJob(dateString string)  {
 			}
 		}
 	}
+	if len(tmpActionParamObjList) > 0 {
+		tmpArchiveActionList := ArchiveActionList{}
+		for _,vvv := range tmpActionParamObjList {
+			tmpArchiveActionList = append(tmpArchiveActionList, vvv)
+		}
+		actionParamList = append(actionParamList, &tmpArchiveActionList)
+	}
 	go checkJobStatus()
 	for _,v := range actionParamList {
 		jobChannelList <- *v
@@ -93,7 +103,38 @@ func CreateJob(dateString string)  {
 func consumeJob()  {
 	for {
 		param := <- jobChannelList
-		go archiveAction(param)
+		if len(param) == 0 {
+			continue
+		}
+		tmpUnixCount := 0
+		var concurrentJobList []ArchiveActionList
+		tmpJobList := ArchiveActionList{}
+		for _,v := range param {
+			tmpUnixCount ++
+			tmpJobList = append(tmpJobList, v)
+			if tmpUnixCount >= maxUnitNum {
+				concurrentJobList = append(concurrentJobList, tmpJobList)
+				tmpJobList = ArchiveActionList{}
+				tmpUnixCount = 0
+			}
+		}
+		if len(tmpJobList) > 0 {
+			concurrentJobList = append(concurrentJobList, tmpJobList)
+		}
+		log.Printf("start consume job,length:%d ,concurrent:%d \n", len(param), len(concurrentJobList))
+		startTime := time.Now()
+		wg := sync.WaitGroup{}
+		for _,job := range concurrentJobList {
+			wg.Add(1)
+			go func(jobList ArchiveActionList) {
+				archiveAction(jobList)
+				wg.Done()
+			}(job)
+		}
+		wg.Wait()
+		endTime := time.Now()
+		useTime := float64(endTime.Sub(startTime).Nanoseconds()) / 1e6
+		log.Printf("done with consume job,use time: %.3f ms", useTime)
 	}
 }
 
@@ -105,6 +146,7 @@ func checkJobStatus()  {
 			log.Printf("archive job done \n")
 			break
 		}
+		time.Sleep(10*time.Second)
 	}
 }
 
diff --git a/monitor-agent/node_exporter/VERSION b/monitor-agent/node_exporter/VERSION
index f21a2fa17..94871f509 100644
--- a/monitor-agent/node_exporter/VERSION
+++ b/monitor-agent/node_exporter/VERSION
@@ -1 +1 @@
-1.10.0(base1.0.0)
\ No newline at end of file
+1.10.0(base1.0.1)
\ No newline at end of file
diff --git a/monitor-agent/node_exporter/collector/log_monitor_linux.go b/monitor-agent/node_exporter/collector/log_monitor_linux.go
index 1e73cf30d..fab0820d0 100644
--- a/monitor-agent/node_exporter/collector/log_monitor_linux.go
+++ b/monitor-agent/node_exporter/collector/log_monitor_linux.go
@@ -160,14 +160,10 @@ func (c *logCollectorObj) getRows(keyword string,value,lastValue float64) []logK
 	c.Lock.RLock()
 	for _,v := range c.Rule {
 		if v.Keyword == keyword {
-			for _,vv := range v.FetchRow {
-				if vv.Index > lastValue && vv.Index <= value {
-					data = append(data, logKeywordFetchObj{Content: vv.Content})
-				}
-				//if (nowTimestamp-vv.Timestamp) <= 10 {
-				//	data = append(data, logKeywordFetchObj{Timestamp: vv.Timestamp, Content: vv.Content})
-				//}
+			if len(v.FetchRow) == 0 {
+				continue
 			}
+			data = append(data, logKeywordFetchObj{Content: v.FetchRow[len(v.FetchRow)-1].Content})
 		}
 	}
 	c.Lock.RUnlock()
diff --git a/monitor-server/api/api.go b/monitor-server/api/api.go
index 3488e4079..45d17b58f 100644
--- a/monitor-server/api/api.go
+++ b/monitor-server/api/api.go
@@ -1,20 +1,20 @@
 package api
 
 import (
-	"github.com/gin-gonic/gin"
-	m "github.com/WeBankPartners/open-monitor/monitor-server/models"
-	"github.com/gin-contrib/cors"
-	"github.com/WeBankPartners/open-monitor/monitor-server/api/v1/user"
-	"net/http"
-	"github.com/swaggo/gin-swagger"
-	"github.com/swaggo/gin-swagger/swaggerFiles"
 	"fmt"
-	"github.com/WeBankPartners/open-monitor/monitor-server/api/v1/dashboard"
 	"github.com/WeBankPartners/open-monitor/monitor-server/api/v1/agent"
 	"github.com/WeBankPartners/open-monitor/monitor-server/api/v1/alarm"
+	"github.com/WeBankPartners/open-monitor/monitor-server/api/v1/dashboard"
+	"github.com/WeBankPartners/open-monitor/monitor-server/api/v1/user"
 	_ "github.com/WeBankPartners/open-monitor/monitor-server/docs"
-	"time"
 	"github.com/WeBankPartners/open-monitor/monitor-server/middleware/log"
+	m "github.com/WeBankPartners/open-monitor/monitor-server/models"
+	"github.com/gin-contrib/cors"
+	"github.com/gin-gonic/gin"
+	"github.com/swaggo/gin-swagger"
+	"github.com/swaggo/gin-swagger/swaggerFiles"
+	"net/http"
+	"time"
 )
 
 func InitHttpServer(exportAgent bool) {
@@ -225,6 +225,6 @@ func httpLogHandle() gin.HandlerFunc {
 	return func(c *gin.Context) {
 		start := time.Now()
 		c.Next()
-		log.Logger.Info("request", log.String("url", c.Request.RequestURI), log.String("method",c.Request.Method), log.Int("code",c.Writer.Status()), log.String("ip",c.ClientIP()), log.Float64("cost_second",time.Now().Sub(start).Seconds()))
+		log.Logger.Info("request", log.String("url", c.Request.RequestURI), log.String("method", c.Request.Method), log.Int("code", c.Writer.Status()), log.String("operator", c.GetString("operatorName")), log.String("ip", c.ClientIP()), log.Int64("cost_time", time.Now().Sub(start).Milliseconds()))
 	}
 }
\ No newline at end of file
diff --git a/monitor-server/api/v1/agent/export.go b/monitor-server/api/v1/agent/export.go
index 19e1fd4d0..90caaf4b2 100644
--- a/monitor-server/api/v1/agent/export.go
+++ b/monitor-server/api/v1/agent/export.go
@@ -1,18 +1,17 @@
 package agent
 
 import (
-	"github.com/gin-gonic/gin"
-	"strings"
+	"encoding/json"
+	"fmt"
 	mid "github.com/WeBankPartners/open-monitor/monitor-server/middleware"
+	"github.com/WeBankPartners/open-monitor/monitor-server/middleware/log"
 	m "github.com/WeBankPartners/open-monitor/monitor-server/models"
-	"net/http"
-	"fmt"
 	"github.com/WeBankPartners/open-monitor/monitor-server/services/db"
+	"github.com/gin-gonic/gin"
 	"io/ioutil"
-	"encoding/json"
-	"github.com/WeBankPartners/open-monitor/monitor-server/api/v1/alarm"
+	"net/http"
 	"strconv"
-	"github.com/WeBankPartners/open-monitor/monitor-server/middleware/log"
+	"strings"
 )
 
 type resultObj struct {
@@ -263,19 +262,19 @@ func autoAddAppPathConfig(param m.RegisterParamNew, paths string) error {
 	if hostEndpoint.Id <= 0 {
 		return fmt.Errorf("Host endpoint with ip:%s can not find,please register this host first ", param.Ip)
 	}
-	var businessTables []*m.BusinessMonitorTable
+	var businessTables []*m.BusinessUpdatePathObj
 	for _,v := range tmpPathList {
-		businessTables = append(businessTables, &m.BusinessMonitorTable{EndpointId:hostEndpoint.Id, Path:v, OwnerEndpoint:fmt.Sprintf("%s_%s_%s", param.Name, param.Ip, param.Type)})
+		businessTables = append(businessTables, &m.BusinessUpdatePathObj{Path:v, OwnerEndpoint:fmt.Sprintf("%s_%s_%s", param.Name, param.Ip, param.Type)})
 	}
-	err := db.UpdateAppendBusiness(m.BusinessUpdateDto{EndpointId:hostEndpoint.Id, PathList:[]*m.BusinessUpdatePathObj{}})
+	err := db.UpdateAppendBusiness(m.BusinessUpdateDto{EndpointId:hostEndpoint.Id, PathList:businessTables})
 	if err != nil {
 		log.Logger.Error("Update endpoint business table error", log.Error(err))
 		return err
 	}
-	err = alarm.UpdateNodeExporterBusinessConfig(hostEndpoint.Id)
-	if err != nil {
-		log.Logger.Error("Update business config error", log.Error(err))
-	}
+	//err = alarm.UpdateNodeExporterBusinessConfig(hostEndpoint.Id)
+	//if err != nil {
+	//	log.Logger.Error("Update business config error", log.Error(err))
+	//}
 	return err
 }
 
diff --git a/monitor-server/api/v1/alarm/alarm.go b/monitor-server/api/v1/alarm/alarm.go
index f42d48ca1..726e04d47 100644
--- a/monitor-server/api/v1/alarm/alarm.go
+++ b/monitor-server/api/v1/alarm/alarm.go
@@ -40,18 +40,26 @@ func AcceptAlertMsg(c *gin.Context)  {
 				sortTagList = append(sortTagList, &m.DefaultSortObj{Key:labelKey, Value:labelValue})
 			}
 			sort.Sort(sortTagList)
+			var guidTagString,eGuidTagString string
 			for _,label := range sortTagList {
 				if label.Key == "strategy_id" || label.Key == "job" || label.Key == "instance" || label.Key == "alertname" {
 					continue
 				}
+				if label.Key == "guid" {
+					guidTagString = label.Value
+				}
+				if label.Key == "e_guid" {
+					eGuidTagString = label.Value
+				}
 				tmpLabelValue := label.Value
-				//if label.Key == "command" {
-				//	if len(label.Value) > 150 {
-				//		tmpLabelValue = label.Value[:150]
-				//	}
-				//}
 				tmpTags += fmt.Sprintf("%s:%s^", label.Key, tmpLabelValue)
 			}
+			if guidTagString != "" && eGuidTagString != "" {
+				if guidTagString != eGuidTagString {
+					log.Logger.Warn("EGuid diff with guid,ignore", log.String("guid", guidTagString), log.String("e_guid", eGuidTagString))
+					continue
+				}
+			}
 			if tmpTags != "" {
 				tmpTags = tmpTags[:len(tmpTags)-1]
 			}
@@ -291,6 +299,7 @@ func QueryProblemAlarm(c *gin.Context)  {
 			return
 		}
 		var highCount,mediumCount,lowCount int
+		metricMap := make(map[string]int)
 		for _,v := range data {
 			if v.SPriority == "high" {
 				highCount += 1
@@ -301,11 +310,16 @@ func QueryProblemAlarm(c *gin.Context)  {
 			if v.SPriority == "low" {
 				lowCount += 1
 			}
+			if _,b:=metricMap[v.SMetric];b {
+				metricMap[v.SMetric] += 1
+			}else{
+				metricMap[v.SMetric] = 1
+			}
 		}
 		if len(data) == 0 {
 			data = []*m.AlarmProblemQuery{}
 		}
-		result := m.AlarmProblemQueryResult{Data:data,High:highCount,Mid:mediumCount,Low:lowCount}
+		result := m.AlarmProblemQueryResult{Data:data,High:highCount,Mid:mediumCount,Low:lowCount,MetricMap: metricMap}
 		mid.ReturnSuccessData(c, result)
 	}else{
 		mid.ReturnValidateError(c, err.Error())
diff --git a/monitor-server/api/v1/dashboard/dashboard.go b/monitor-server/api/v1/dashboard/dashboard.go
index f1f21c7f5..34f0e0f8a 100644
--- a/monitor-server/api/v1/dashboard/dashboard.go
+++ b/monitor-server/api/v1/dashboard/dashboard.go
@@ -6,6 +6,7 @@ import (
 	"github.com/WeBankPartners/open-monitor/monitor-server/services/db"
 	ds "github.com/WeBankPartners/open-monitor/monitor-server/services/datasource"
 	"github.com/gin-gonic/gin"
+	"sort"
 	"strconv"
 	"strings"
 	"time"
@@ -779,7 +780,7 @@ func GetPieChart(c *gin.Context)  {
 func MainSearch(c *gin.Context)  {
 	endpoint := c.Query("search")
 	//limit := c.Query("limit")
-	if endpoint == ""{
+	if endpoint == "" {
 		mid.ReturnParamEmptyError(c, "search")
 		return
 	}
@@ -796,14 +797,9 @@ func MainSearch(c *gin.Context)  {
 	for _,v := range result {
 		v.OptionTypeName = v.OptionType
 	}
-	if len(result) < 10 {
-		sysResult := db.SearchRecursivePanel(endpoint)
-		for _, v := range sysResult {
-			if len(result) >= 10 {
-				break
-			}
-			result = append(result, v)
-		}
+	sysResult := db.SearchRecursivePanel(endpoint)
+	for _, v := range sysResult {
+		result = append(result, v)
 	}
 	if tmpFlag {
 		var tmpResult []*m.OptionModel
@@ -817,7 +813,10 @@ func MainSearch(c *gin.Context)  {
 			result = tmpResult
 		}
 	}
-	mid.ReturnSuccessData(c, result)
+	var sortOptionList m.OptionModelSortList
+	sortOptionList = append(sortOptionList, result...)
+	sort.Sort(sortOptionList)
+	mid.ReturnSuccessData(c, sortOptionList)
 }
 
 func GetPromMetric(c *gin.Context)  {
diff --git a/monitor-server/api/v1/user/auth.go b/monitor-server/api/v1/user/auth.go
index 36386339a..b0534135b 100644
--- a/monitor-server/api/v1/user/auth.go
+++ b/monitor-server/api/v1/user/auth.go
@@ -173,25 +173,26 @@ func AuthRequired() gin.HandlerFunc {
 			if !m.Config().Http.Session.Enable {
 				auToken := c.GetHeader("Authorization")
 				if auToken != "" {
-					_, err := mid.DecodeCoreToken(auToken, m.CoreJwtKey)
+					coreToken, err := mid.DecodeCoreToken(auToken, m.CoreJwtKey)
 					if err != nil {
 						mid.ReturnTokenError(c)
 						c.Abort()
 					} else {
+						c.Set("operatorName", coreToken.User)
 						c.Next()
 					}
 				} else {
 					mid.ReturnTokenError(c)
 					c.Abort()
 				}
-				//c.Next()
-				//return
 			} else {
 				auToken := c.GetHeader("X-Auth-Token")
 				if auToken != "" {
-					if mid.IsActive(auToken, c.ClientIP()) {
+					isOk,operator := mid.IsActive(auToken, c.ClientIP())
+					if isOk {
+						c.Set("operatorName", operator)
 						c.Next()
-					} else {
+					}else {
 						mid.ReturnTokenError(c)
 						c.Abort()
 					}
diff --git a/monitor-server/middleware/session.go b/monitor-server/middleware/session.go
index 4d0eae0c2..154721c48 100644
--- a/monitor-server/middleware/session.go
+++ b/monitor-server/middleware/session.go
@@ -145,10 +145,10 @@ func GetSessionData(sId string) m.Session {
 	return result
 }
 
-func IsActive(sId string, clientIp string) bool {
+func IsActive(sId string, clientIp string) (bool,string) {
 	if m.Config().Http.Session.ServerEnable {
 		if sId == m.Config().Http.Session.ServerToken {
-			return true
+			return true,"server"
 		}
 	}
 	var tmpUser string
@@ -169,7 +169,7 @@ func IsActive(sId string, clientIp string) bool {
 			recordRequestLock.RUnlock()
 			if !localContain {
 				delete(LocalMem, sId)
-				return false
+				return false,""
 			}
 		}
 		localContain = true
@@ -189,7 +189,7 @@ func IsActive(sId string, clientIp string) bool {
 		RecordRequestMap[fmt.Sprintf("%s_%s", tmpUser,clientIp)] = time.Now().Unix()
 		recordRequestLock.Unlock()
 	}
-	return localContain
+	return localContain,tmpUser
 }
 
 func DelSession(sId string) {
diff --git a/monitor-server/models/alarm.go b/monitor-server/models/alarm.go
index 19869afab..13d6c3324 100644
--- a/monitor-server/models/alarm.go
+++ b/monitor-server/models/alarm.go
@@ -73,6 +73,7 @@ type AlarmProblemQuery struct {
 	StartValue  float64  `json:"start_value"`
 	Start  time.Time  `json:"start"`
 	StartString  string  `json:"start_string"`
+	EndValue  float64  `json:"end_value"`
 	End  time.Time  `json:"end"`
 	EndString  string  `json:"end_string"`
 	IsLogMonitor  bool  `json:"is_log_monitor"`
@@ -86,6 +87,7 @@ type AlarmProblemQueryResult struct {
 	High  int  `json:"high"`
 	Mid   int  `json:"mid"`
 	Low   int  `json:"low"`
+	MetricMap map[string]int  `json:"metric"`
 }
 
 type AlarmProblemList []*AlarmProblemQuery
diff --git a/monitor-server/models/dashboard.go b/monitor-server/models/dashboard.go
index 932e9572c..fb99c398c 100644
--- a/monitor-server/models/dashboard.go
+++ b/monitor-server/models/dashboard.go
@@ -12,6 +12,20 @@ type SearchModel struct {
 	RefreshMessage bool  `json:"refresh_message"`
 }
 
+type OptionModelSortList []*OptionModel
+
+func (e OptionModelSortList) Len() int {
+	return len(e)
+}
+
+func (e OptionModelSortList) Swap(i,j int)  {
+	e[i], e[j] = e[j], e[i]
+}
+
+func (e OptionModelSortList) Less(i,j int) bool {
+	return len(e[i].OptionText) < len(e[j].OptionText)
+}
+
 type OptionModel struct {
 	Id  int  `json:"id"`
 	OptionValue  string  `json:"option_value"`
diff --git a/monitor-server/services/datasource/prometheus.go b/monitor-server/services/datasource/prometheus.go
index 841bf5d36..b67ee6c22 100644
--- a/monitor-server/services/datasource/prometheus.go
+++ b/monitor-server/services/datasource/prometheus.go
@@ -201,9 +201,10 @@ func GetSerialName(query *m.QueryMonitorData,tagMap map[string]string,dataLength
 	}
 	if legend == "$app_metric" {
 		if _,b:=tagMap["key"];b {
-			tmpName = fmt.Sprintf("%s{agg=%s,%s}", tagMap["key"], tagMap["agg"], tagMap["tags"])
-			if tmpName[:len(tmpName)-1] == "," {
-				tmpName = tmpName[:len(tmpName)-1]
+			if tagMap["tags"] != "" {
+				tmpName = fmt.Sprintf("%s{agg=%s,%s}", tagMap["key"], tagMap["agg"], tagMap["tags"])
+			}else{
+				tmpName = fmt.Sprintf("%s{agg=%s}", tagMap["key"], tagMap["agg"])
 			}
 		}else{
 			tmpName = metric
diff --git a/monitor-server/services/db/agent.go b/monitor-server/services/db/agent.go
index 3e4fe4a85..8fffa65d5 100644
--- a/monitor-server/services/db/agent.go
+++ b/monitor-server/services/db/agent.go
@@ -240,7 +240,7 @@ func SearchRecursivePanel(search string) []*m.OptionModel {
 	if search == "." {
 		search = ""
 	}
-	sql := `SELECT * FROM panel_recursive WHERE display_name LIKE  '%` + search + `%' limit 10`
+	sql := `SELECT * FROM panel_recursive WHERE display_name LIKE  '%` + search + `%' limit 100`
 	x.SQL(sql).Find(&prt)
 	for _,v := range prt {
 		//options = append(options, &m.OptionModel{Id:-1, OptionValue:fmt.Sprintf("%s:sys", v.Guid), OptionText:v.DisplayName})
diff --git a/monitor-server/services/db/alarm.go b/monitor-server/services/db/alarm.go
index 98b5dbf1f..3d7cd57b4 100644
--- a/monitor-server/services/db/alarm.go
+++ b/monitor-server/services/db/alarm.go
@@ -544,71 +544,69 @@ func GetEndpointsByGrp(grpId int) (error, []*m.EndpointTable) {
 
 func GetAlarms(query m.AlarmTable, limit int, extLogMonitor, extOpenAlarm bool) (error, m.AlarmProblemList) {
 	var result []*m.AlarmProblemQuery
-	var whereSql, extWhereSql string
-	var params, extParams []interface{}
+	var whereSql string
+	var params []interface{}
 	if query.Id > 0 {
-		whereSql += " and t1.id=? "
+		whereSql += " and id=? "
 		params = append(params, query.Id)
 	}
 	if query.StrategyId > 0 {
-		whereSql += " and t1.strategy_id=? "
+		whereSql += " and strategy_id=? "
 		params = append(params, query.StrategyId)
 	}
 	if query.Endpoint != "" {
-		whereSql += " and t1.endpoint=? "
+		whereSql += " and endpoint=? "
 		params = append(params, query.Endpoint)
 	}
 	if query.SMetric != "" {
-		whereSql += " and t1.s_metric=? "
+		whereSql += " and s_metric=? "
 		params = append(params, query.SMetric)
 	}
 	if query.SCond != "" {
-		whereSql += " and t1.s_cond=? "
+		whereSql += " and s_cond=? "
 		params = append(params, query.SCond)
 	}
 	if query.SLast != "" {
-		whereSql += " and t1.s_last=? "
+		whereSql += " and s_last=? "
 		params = append(params, query.SLast)
 	}
 	if query.SPriority != "" {
-		whereSql += " and t1.s_priority=? "
+		whereSql += " and s_priority=? "
 		params = append(params, query.SPriority)
 	}
 	if query.Tags != "" {
-		whereSql += " and t1.tags=? "
+		whereSql += " and tags=? "
 		params = append(params, query.Tags)
 	}
-	extWhereSql = whereSql
-	extParams = params
 	if query.Status != "" {
-		whereSql += " and t1.status=? "
+		whereSql += " and status=? "
 		params = append(params, query.Status)
-		if query.Status == "firing" {
-			extWhereSql += "and t1.status!='closed' "
-		}
 	}
 	if !query.Start.IsZero() {
-		whereSql += fmt.Sprintf(" and t1.start>='%s' ", query.Start.Format(m.DatetimeFormat))
+		whereSql += fmt.Sprintf(" and start>='%s' ", query.Start.Format(m.DatetimeFormat))
 	}
 	if !query.End.IsZero() {
-		whereSql += fmt.Sprintf(" and t1.end<='%s' ", query.End.Format(m.DatetimeFormat))
-	}
-	var sql string
-	if extLogMonitor {
-		for _, v := range extParams {
-			params = append(params, v)
-		}
-		sql = `SELECT t3.* FROM (
-				SELECT t1.*,'' path,'' keyword FROM alarm t1 WHERE t1.s_metric<>'log_monitor' ` + whereSql + `
-				UNION
-				SELECT t1.*,t2.path,t2.keyword FROM alarm t1 LEFT JOIN log_monitor t2 ON t1.strategy_id=t2.strategy_id WHERE t1.s_metric='log_monitor' ` + extWhereSql + `
-				) t3 ORDER BY t3.id DESC`
-	} else {
-		sql = "SELECT * FROM alarm t1 WHERE 1=1 " + whereSql + " ORDER BY t1.id DESC "
-		if limit > 0 {
-			sql += fmt.Sprintf(" LIMIT %d", limit)
-		}
-	}
+		whereSql += fmt.Sprintf(" and end<='%s' ", query.End.Format(m.DatetimeFormat))
+	}
+	sql := "SELECT * FROM alarm where 1=1 " + whereSql + " ORDER BY id DESC "
+	if limit > 0 {
+		sql += fmt.Sprintf(" LIMIT %d", limit)
+	}
+	//if extLogMonitor {
+	//	for _, v := range extParams {
+	//		params = append(params, v)
+	//	}
+	//	sql = `SELECT t3.* FROM (
+	//			SELECT t1.*,'' path,'' keyword FROM alarm t1 WHERE t1.s_metric<>'log_monitor' ` + whereSql + `
+	//			UNION
+	//			SELECT t1.*,t2.path,t2.keyword FROM alarm t1 LEFT JOIN log_monitor t2 ON t1.strategy_id=t2.strategy_id WHERE t1.s_metric='log_monitor' ` + extWhereSql + `
+	//			) t3 ORDER BY t3.id DESC`
+	//} else {
+	//	sql = "SELECT * FROM alarm t1 WHERE 1=1 " + whereSql + " ORDER BY t1.id DESC "
+	//	if limit > 0 {
+	//		sql += fmt.Sprintf(" LIMIT %d", limit)
+	//	}
+	//}
 	err := x.SQL(sql, params...).Find(&result)
 	if err != nil {
 		log.Logger.Error("Get alarms fail", log.Error(err))
@@ -616,8 +614,21 @@ func GetAlarms(query m.AlarmTable, limit int, extLogMonitor, extOpenAlarm bool)
 	for _, v := range result {
 		v.StartString = v.Start.Format(m.DatetimeFormat)
 		v.EndString = v.End.Format(m.DatetimeFormat)
-		if v.Path != "" {
+		if v.SMetric == "log_monitor" {
 			v.IsLogMonitor = true
+			if v.EndValue > 0 {
+				v.Start,v.End = v.End,v.Start
+				v.StartValue = v.EndValue - v.StartValue + 1
+				if strings.Contains(v.Content, "^^") {
+					v.Content = fmt.Sprintf("%s: %s <br/>%s: %s", v.StartString, v.Content[:strings.Index(v.Content, "^^")], v.EndString, v.Content[strings.Index(v.Content, "^^")+2:])
+				}
+				v.StartString = v.EndString
+			}else{
+				v.StartValue = 1
+				if strings.HasSuffix(v.Content, "^^") {
+					v.Content = v.StartString +": " + v.Content[:len(v.Content)-2]
+				}
+			}
 		}
 		if strings.Contains(v.Content, "\n") {
 			v.Content = strings.ReplaceAll(v.Content, "\n", "<br/>")
@@ -1228,29 +1239,48 @@ func QueryAlarmBySql(sql string, params []interface{}) (err error, result m.Alar
 	if err != nil || len(alarmQuery) == 0 {
 		return err, result
 	}
-	var logMonitorStrategyIds []string
+	//var logMonitorStrategyIds []string
 	for _, v := range alarmQuery {
+		v.StartString = v.Start.Format(m.DatetimeFormat)
+		v.EndString = v.End.Format(m.DatetimeFormat)
 		if v.SMetric == "log_monitor" {
-			logMonitorStrategyIds = append(logMonitorStrategyIds, strconv.Itoa(v.StrategyId))
-		}
-	}
-	if len(logMonitorStrategyIds) > 0 {
-		var logMonitorQuery []*m.LogMonitorTable
-		x.SQL("SELECT * FROM log_monitor WHERE strategy_id IN (" + strings.Join(logMonitorStrategyIds, ",") + ")").Find(&logMonitorQuery)
-		if len(logMonitorQuery) > 0 {
-			for _, v := range alarmQuery {
-				if v.SMetric == "log_monitor" {
-					for _, vv := range logMonitorQuery {
-						if v.StrategyId == vv.StrategyId {
-							v.Path = vv.Path
-							v.Keyword = vv.Keyword
-							break
-						}
-					}
+			v.IsLogMonitor = true
+			if v.EndValue > 0 {
+				v.Start,v.End = v.End,v.Start
+				v.StartValue = v.EndValue - v.StartValue + 1
+				if strings.Contains(v.Content, "^^") {
+					v.Content = fmt.Sprintf("%s: %s <br/>%s: %s", v.StartString, v.Content[:strings.Index(v.Content, "^^")], v.EndString, v.Content[strings.Index(v.Content, "^^")+2:])
+				}
+				v.StartString = v.EndString
+			}else{
+				v.StartValue = 1
+				if strings.HasSuffix(v.Content, "^^") {
+					v.Content = v.StartString +": " + v.Content[:len(v.Content)-2]
 				}
 			}
 		}
+		if strings.Contains(v.Content, "\n") {
+			v.Content = strings.ReplaceAll(v.Content, "\n", "<br/>")
+		}
 	}
+	//if len(logMonitorStrategyIds) > 0 {
+	//	var logMonitorQuery []*m.LogMonitorTable
+	//	x.SQL("SELECT * FROM log_monitor WHERE strategy_id IN (" + strings.Join(logMonitorStrategyIds, ",") + ")").Find(&logMonitorQuery)
+	//	if len(logMonitorQuery) > 0 {
+	//		for _, v := range alarmQuery {
+	//			if v.SMetric == "log_monitor" {
+	//				for _, vv := range logMonitorQuery {
+	//					if v.StrategyId == vv.StrategyId {
+	//						v.Path = vv.Path
+	//						v.Keyword = vv.Keyword
+	//						break
+	//					}
+	//				}
+	//			}
+	//		}
+	//	}
+	//}
+	metricMap := make(map[string]int)
 	for _, v := range alarmQuery {
 		if v.SPriority == "high" {
 			result.High += 1
@@ -1259,9 +1289,14 @@ func QueryAlarmBySql(sql string, params []interface{}) (err error, result m.Alar
 		} else if v.SPriority == "low" {
 			result.Low += 1
 		}
-		v.StartString = v.Start.Format(m.DatetimeFormat)
+		if _,b:=metricMap[v.SMetric];b {
+			metricMap[v.SMetric] += 1
+		}else{
+			metricMap[v.SMetric] = 1
+		}
 	}
 	result.Data = alarmQuery
+	result.MetricMap = metricMap
 	return err, result
 }
 
@@ -1283,7 +1318,7 @@ func QueryHistoryAlarm(param m.QueryHistoryAlarmParam) (err error, result m.Alar
 		whereSql += fmt.Sprintf(" AND s_metric='%s' ", param.Metric)
 	}
 	if param.Filter == "all" {
-		sql = "SELECT * FROM alarm WHERE not (start>'" + endString + "' OR end<='" + startString + "') " + whereSql + " ORDER BY id DESC"
+		sql = "SELECT * FROM alarm WHERE start<='" + endString + "' OR end>='" + startString + "' " + whereSql + " ORDER BY id DESC"
 	}
 	if param.Filter == "start" {
 		sql = "SELECT * FROM alarm WHERE start>='" + startString + "' AND start<'" + endString + "' " + whereSql + " ORDER BY id DESC"
diff --git a/monitor-server/services/db/cron.go b/monitor-server/services/db/cron.go
index 43ddede1d..e07843235 100644
--- a/monitor-server/services/db/cron.go
+++ b/monitor-server/services/db/cron.go
@@ -159,10 +159,10 @@ func StartCheckLogKeyword()  {
 
 func CheckLogKeyword()  {
 	log.Logger.Debug("start check log keyword")
-	nowTime := time.Now().Unix()
+	nowTime := time.Now()
 	var queryParam m.QueryMonitorData
-	queryParam.Start = nowTime - 10
-	queryParam.End = nowTime
+	queryParam.Start = nowTime.Unix() - 10
+	queryParam.End = nowTime.Unix()
 	queryParam.Step = 10
 	queryParam.PromQ = "node_log_monitor_count_total"
 	queryParam.Legend = "$custom_all"
@@ -204,32 +204,60 @@ func CheckLogKeyword()  {
 				var oldValue float64
 				if lastValue > 0 {
 					needAdd := true
+					var fetchAlarm m.AlarmTable
 					for _,tmpAlarm := range alarmTable {
 						if tmpAlarm.Tags == lmt.Tags {
 							oldValue = tmpAlarm.StartValue
-							if lastValue <= tmpAlarm.StartValue {
+							if tmpAlarm.EndValue > 0 {
+								oldValue = tmpAlarm.EndValue
+							}
+							if lastValue <= oldValue {
 								needAdd = false
+							}else{
+								fetchAlarm = *tmpAlarm
 							}
 							break
 						}
 					}
 					if needAdd {
 						tmpContent := getLogMonitorRows(tmpEndpointObj.Ip, v.Path, v.Keyword,lastValue,oldValue)
-						if len(tmpContent) > 500 {
-							tmpContent = tmpContent[:500]
+						if len(tmpContent) > 240 {
+							tmpContent = tmpContent[:240]
+						}
+						if fetchAlarm.Id > 0 && fetchAlarm.Status == "firing" {
+							tmpContent = strings.Split(fetchAlarm.Content, "^^")[0] + "^^" + tmpContent
+							addAlarmRows = append(addAlarmRows, &m.AlarmTable{Id: fetchAlarm.Id, StrategyId: 0, Endpoint: lmt.Endpoint, Status: "firing", SMetric: "log_monitor", SExpr: "node_log_monitor_count_total", SCond: ">0", SLast: "10s", SPriority: v.Priority, Content: tmpContent, Tags: lmt.Tags, StartValue: fetchAlarm.StartValue, EndValue: lastValue, Start: fetchAlarm.Start, End: nowTime})
+						}else {
+							tmpContent = tmpContent + "^^"
+							addAlarmRows = append(addAlarmRows, &m.AlarmTable{StrategyId: 0, Endpoint: lmt.Endpoint, Status: "firing", SMetric: "log_monitor", SExpr: "node_log_monitor_count_total", SCond: ">0", SLast: "10s", SPriority: v.Priority, Content: tmpContent, Tags: lmt.Tags, StartValue: lastValue, Start: nowTime})
 						}
-						addAlarmRows = append(addAlarmRows, &m.AlarmTable{StrategyId:0, Endpoint:lmt.Endpoint,Status:"firing",SMetric:"log_monitor",SExpr:"node_log_monitor_count_total",SCond:">0",SLast:"10s",SPriority:v.Priority,Content:tmpContent,Tags:lmt.Tags,StartValue:lastValue})
 					}
 				}
 			}
 		}
 	}
 	if len(addAlarmRows) > 0 {
-		err = UpdateAlarms(addAlarmRows)
+		var actions []*Action
+		for _,v := range addAlarmRows {
+			tmpAction := Action{}
+			if v.Id > 0 {
+				tmpAction.Sql = "UPDATE alarm SET content=?,end_value=?,end=? WHERE id=?"
+				tmpAction.Param = []interface{}{v.Content, v.EndValue, v.End.Format(m.DatetimeFormat), v.Id}
+			}else{
+				tmpAction.Sql = "INSERT INTO alarm(strategy_id,endpoint,status,s_metric,s_expr,s_cond,s_last,s_priority,content,start_value,start,tags) VALUE (?,?,?,?,?,?,?,?,?,?,?,?)"
+				tmpAction.Param = []interface{}{v.StrategyId,v.Endpoint,v.Status,v.SMetric,v.SExpr,v.SCond,v.SLast,v.SPriority,v.Content,v.StartValue,v.Start.Format(m.DatetimeFormat),v.Tags}
+			}
+			actions = append(actions, &tmpAction)
+		}
+		err = Transaction(actions)
+		//err = UpdateAlarms(addAlarmRows)
 		if err != nil {
 			log.Logger.Error("Update alarm table fail", log.Error(err))
 		}
 		for _,v := range addAlarmRows {
+			if v.Id > 0 {
+				continue
+			}
 			var tmpAlarmTable []*m.AlarmTable
 			x.SQL("SELECT id FROM alarm WHERE status='firing' AND tags=?", v.Tags).Find(&tmpAlarmTable)
 			if len(tmpAlarmTable) > 0 {
diff --git a/monitor-server/services/db/dashboard.go b/monitor-server/services/db/dashboard.go
index 778cf12d9..0d8c2daa1 100644
--- a/monitor-server/services/db/dashboard.go
+++ b/monitor-server/services/db/dashboard.go
@@ -175,7 +175,7 @@ func SearchHost(endpoint string) (error, []*m.OptionModel) {
 	options := []*m.OptionModel{}
 	var hosts []*m.EndpointTable
 	endpoint = `%` + endpoint + `%`
-	err := x.SQL("SELECT * FROM endpoint WHERE (ip LIKE ? OR name LIKE ?) and export_type<>'custom' order by export_type,ip limit 10", endpoint, endpoint).Find(&hosts)
+	err := x.SQL("SELECT * FROM endpoint WHERE (ip LIKE ? OR name LIKE ?) and export_type<>'custom' order by export_type,ip limit 100", endpoint, endpoint).Find(&hosts)
 	if err != nil {
 		log.Logger.Error("Search host fail", log.Error(err))
 		return err,options
diff --git a/monitor-server/services/db/ping_exporter_ext.go b/monitor-server/services/db/ping_exporter_ext.go
index 57eb926e6..921e4afdd 100644
--- a/monitor-server/services/db/ping_exporter_ext.go
+++ b/monitor-server/services/db/ping_exporter_ext.go
@@ -104,4 +104,5 @@ func requestPingExporter(address string,objList []*m.PingExportSourceObj)  {
 	}else{
 		log.Logger.Info("Request ping exporter success", log.String("address", address))
 	}
+	resp.Body.Close()
 }
\ No newline at end of file
diff --git a/monitor-server/services/prom/file_sd.go b/monitor-server/services/prom/file_sd.go
index 4ec827a96..4febfc9d8 100644
--- a/monitor-server/services/prom/file_sd.go
+++ b/monitor-server/services/prom/file_sd.go
@@ -27,6 +27,9 @@ func AddSdEndpoint(param m.ServiceDiscoverFileObj) []int {
 				stepList = append(stepList, v.Step)
 				v.Step = param.Step
 			}
+			if v.Address != param.Address {
+				v.Address = param.Address
+			}
 			exist = true
 			break
 		}
diff --git a/monitor-ui/src/assets/locale/lang/en.json b/monitor-ui/src/assets/locale/lang/en.json
index a402b09eb..055a3a46f 100755
--- a/monitor-ui/src/assets/locale/lang/en.json
+++ b/monitor-ui/src/assets/locale/lang/en.json
@@ -205,5 +205,6 @@
   "token": "TOKEN",
   "rule": "Rule",
   "addMetricConfig": "Add Metric",
-  "addStringMap": "Add Mapping"
+  "addStringMap": "Add Mapping",
+  "operationDoc": "Operation Document"
 }
diff --git a/monitor-ui/src/assets/locale/lang/zh-CN.json b/monitor-ui/src/assets/locale/lang/zh-CN.json
index 399d28522..82f6cfb6c 100755
--- a/monitor-ui/src/assets/locale/lang/zh-CN.json
+++ b/monitor-ui/src/assets/locale/lang/zh-CN.json
@@ -205,5 +205,6 @@
   "token": "TOKEN",
   "rule": "规则",
   "addMetricConfig": "新增指标配置",
-  "addStringMap": "新增映射"
+  "addStringMap": "新增映射",
+  "operationDoc": "操作文档"
 }
diff --git a/monitor-ui/src/views/alarm-management.vue b/monitor-ui/src/views/alarm-management.vue
index b5f821962..514625d28 100644
--- a/monitor-ui/src/views/alarm-management.vue
+++ b/monitor-ui/src/views/alarm-management.vue
@@ -103,7 +103,7 @@
                   <label class="col-md-2" style="vertical-align: top;">{{$t('field.endpoint')}}&{{$t('tableKey.s_priority')}}&{{$t('tableKey.start')}}:</label>
                   <Tag type="border" closable @on-close="addParams('endpoint',alarmItem.endpoint)" color="primary">{{alarmItem.endpoint}}</Tag>
                   <Tag type="border" closable @on-close="addParams('priority',alarmItem.s_priority)" color="primary">{{alarmItem.s_priority}}</Tag>
-                  <span>{{alarmItem.start_string}}</span>
+                  <Tag type="border" color="warning">{{alarmItem.start_string}}</Tag>
                 </li>
                 <li>
                   <label class="col-md-2">
@@ -116,7 +116,7 @@
                   </template>
                 </li>
                 <li>
-                  <label class="col-md-2" style="vertical-align: top;">{{$t('details')}}&{{$t('alarmContent')}}:</label>
+                  <label class="col-md-2" style="vertical-align: top;">{{$t('details')}}:</label>
                   <div class="col-md-9" style="display: inline-block;padding:0">
                     <span>
                       <Tag color="default">{{$t('tableKey.start_value')}}:{{alarmItem.start_value}}</Tag>
@@ -125,6 +125,11 @@
                       <Tag color="default" v-if="alarmItem.path">{{$t('tableKey.path')}}:{{alarmItem.path}}</Tag>
                       <Tag color="default" v-if="alarmItem.keyword">{{$t('tableKey.keyword')}}:{{alarmItem.keyword}}</Tag>
                     </span>
+                  </div>
+                </li>
+                <li>
+                  <label class="col-md-2" style="vertical-align: top;">{{$t('alarmContent')}}:</label>
+                  <div class="col-md-9" style="display: inline-block;padding:0">
                     <span style="word-break: break-all;" v-html="alarmItem.content"></span>
                   </div>
                 </li>
diff --git a/monitor-ui/src/views/monitor-config/business-monitor.vue b/monitor-ui/src/views/monitor-config/business-monitor.vue
index 52cd10ace..29bda2864 100644
--- a/monitor-ui/src/views/monitor-config/business-monitor.vue
+++ b/monitor-ui/src/views/monitor-config/business-monitor.vue
@@ -14,8 +14,16 @@
             @on-clear="clearEndpoint"
             >
             <Option v-for="(option, index) in endpointOptions" :value="option.id" :key="index">
-             <Tag color="cyan" class="tag-width" v-if="option.type == 'host'">host</Tag>{{option.option_text}}11</Option>
+             <Tag color="cyan" class="tag-width" v-if="option.type == 'host'">host</Tag>{{option.option_text}}</Option>
           </Select>
+          <span @click="openDoc">
+            <i 
+              class="fa fa-book" 
+              aria-hidden="true" 
+              style="font-size:20px;color:#58a0e6;vertical-align: middle;margin-left:20px">
+            </i>
+            {{$t('operationDoc')}}
+          </span>
         </li>
       </ul>
     </section>
@@ -247,6 +255,9 @@ export default {
     this.$root.$store.commit('changeTableExtendActive', -1)
   },
   methods: {
+    openDoc () {
+      window.open('http://webankpartners.gitee.io/wecube-docs/manual-open-monitor-config/#_6')
+    },
     /*********/
     addEmpty (type) {
       if (!this.ruleModelConfig.addRow[type]) {
diff --git a/wiki/business_config.md b/wiki/business_config.md
new file mode 100644
index 000000000..f65afc2f4
--- /dev/null
+++ b/wiki/business_config.md
@@ -0,0 +1,78 @@
+# Open-Monitor业务指标配置
+
+## 一、	监控方式说明
+#### 1、内容匹配
+通过业务系统打的业务日志来采集业务指标,日志以行为单位,每一行都会去尝试匹配在Open-Monitor业务监控里配置好的正则表达式,如果匹配上了会去尝试解析匹配上的Json字符串,进而拿到里面的key、value。  
+比如说:  
+```
+正则表达式:\[.*\]\[.*\]\[.*\]\[.*\]\[.*\]\[.*\]\[.*\]\[(.*)\]\[.*\]  
+日志行:[INFO][2020-01-01 10:00:00 169][ConsumeMessageThread_9][][20111201A][][][{"costTime":52,"method":”GET","resCode":"200"}][]  
+```
+匹配上了正则后,会去尝试拿小括号()里面匹配上的子字符串做json解析,可以配多段json内容,只是尽量不要里面的key一样,会被覆盖。
+解析后会拿到如下的内容  
+```
+{"costTime":52,"method":”GET","resCode":"200"}
+```
+
+#### 2、指标计算
+因为Prometheus的采集方式是server向client拉数据,间隔现在默认是10秒,所以需要对10秒期间内的多行日志数据指标做聚合,现在支持三种聚合方式:avg(平均),sum(累加),count(计数)。  
+比如说:  
+10秒内的日志每行匹配到的json如下  
+```
+{"costTime":52,"method":”GET","resCode":"200"}  
+{"costTime":137,"method":”POST","resCode":"200"}  
+{"costTime":28,"method":”GET","resCode":"404"}  
+```
+要配置出 请求的平均耗时、总请求数、各方式(GET/POST)的请求数、请求成功率  
+需要配置三组计算规则,计算规则由正则表达式、标签、指标配置、字符映射四部分组成,表达式是为了匹配内容,标签是为了区分要要不同统计规则的key,指标则是要用于最后的指标采集与数值计算,字符映射是用于把value映射成数值,因为时序数据库只能保存数值。  
+三组规则(正则都是一样的):  
+1、  
+```
+正则:\[.*\]\[.*\]\[.*\]\[.*\]\[.*\]\[.*\]\[.*\]\[(.*)\]\[.*\]  
+标签:(空)  
+指标配置:(由key、指标名、聚合方式组成)  
+costTime   app_request_time  avg  
+method    app_request_all_num  count  
+```
+2、
+```
+正则:\[.*\]\[.*\]\[.*\]\[.*\]\[.*\]\[.*\]\[.*\]\[(.*)\]\[.*\]
+标签:method
+指标配置:
+method   app_request_method_num  count
+```
+
+3、
+```
+正则:\[.*\]\[.*\]\[.*\]\[.*\]\[.*\]\[.*\]\[.*\]\[(.*)\]\[.*\]
+标签:resCode
+指标配置:
+resCode   app_request_status_num  count
+```
+
+当聚合规则为count时,其实只是计算它的数量,此时key是什么并不重要,换其它的key也可以,因为标签的存在已经把不同标签value的指标给分隔开来了,以上三个规则会有如下6条指标
+```
+app_request_time{agg=”avg”}  72
+app_request_all_num{agg=”count”}  3
+app_request_method_num{agg=”count”,method=”GET”}  2
+app_request_method_num{agg=”count”,method=”POST”}  1
+app_request_status_num{agg=”count”,resCode=”200”}   2
+app_request_status_num{agg=”count”,resCode=”404”}   1
+```
+
+至此已经可以求出上面四个需求中的三个,请求的平均耗时、总请求数、各方式(GET/POST)的请求数。  
+第四个请求成功率则需要用 app_request_status_num/ app_request_all_num*100% 获得,这个需要在指标设计中配置过新的指标,上面的配置已经把基础数据都给采回来了,在指标设计中通过PromQL(Prometheus的查询表达式)来查出想要的内容。  
+```
+指标名:app_request_success_percent
+表达式:(sum(node_business_monitor_value{key="app_request_status_num",tags="resCode=200"} or vector(0))/sum(node_business_monitor_value{key="app_request_all_num"} or vector(1)))*100
+```
+## 二、	界面配置说明
+在监控配置中找到对应的主机跳转到对应的业务日志监控配置界面。  
+![business_config_01](images/business_config_01.png)
+或直接在界面上的最后一个tab叫业务监控上搜索相应的主机也可以。
+界面的列表结构是以日志path为主,里面套多一层规则列表的形式展现,所以新增的时候是新增一个path,然后再在这path上增加各种规则,界面如下:  
+![business_config_02](images/business_config_02.png)
+规则的表单有如下内容,对应上面第一部分所说的规则样例,有正则、标签(可空)、指标配置、字符串映射(可空)  
+![business_config_03](images/business_config_03.png)
+配置好后可以在对象视图界面看到所采集上来的指标,在最后的Business那一列  
+![business_config_04](images/business_config_04.png)
\ No newline at end of file
diff --git a/wiki/db/monitor_sql_02_base_data_cn.sql b/wiki/db/monitor_sql_02_base_data_cn.sql
index c722b1612..90d46877d 100644
--- a/wiki/db/monitor_sql_02_base_data_cn.sql
+++ b/wiki/db/monitor_sql_02_base_data_cn.sql
@@ -182,4 +182,11 @@ CREATE TABLE `business_monitor_cfg` (
 
 #@v1.10.0.5-begin@;
 update chart set legend='$app_metric' where legend='$key';
-#@v1.10.0.5-end@;
\ No newline at end of file
+#@v1.10.0.5-end@;
+
+#@v1.11.0-begin@;
+create index alarm_endpoint_idx on alarm(endpoint);
+create index alarm_metric_idx on alarm(s_metric);
+create index alarm_status_idx on alarm(status);
+create index alarm_priority_idx on alarm(s_priority);
+#@v1.11.0-end@;
\ No newline at end of file
diff --git a/wiki/db/monitor_sql_02_base_data_en.sql b/wiki/db/monitor_sql_02_base_data_en.sql
index 6062d6cfd..1bf4f1c18 100644
--- a/wiki/db/monitor_sql_02_base_data_en.sql
+++ b/wiki/db/monitor_sql_02_base_data_en.sql
@@ -182,4 +182,11 @@ CREATE TABLE `business_monitor_cfg` (
 
 #@v1.10.0.5-begin@;
 update chart set legend='$app_metric' where legend='$key';
-#@v1.10.0.5-end@;
\ No newline at end of file
+#@v1.10.0.5-end@;
+
+#@v1.11.0-begin@;
+create index alarm_endpoint_idx on alarm(endpoint);
+create index alarm_metric_idx on alarm(s_metric);
+create index alarm_status_idx on alarm(status);
+create index alarm_priority_idx on alarm(s_priority);
+#@v1.11.0-end@;
\ No newline at end of file
diff --git a/wiki/images/business_config_01.png b/wiki/images/business_config_01.png
new file mode 100644
index 000000000..0e960ebfd
Binary files /dev/null and b/wiki/images/business_config_01.png differ
diff --git a/wiki/images/business_config_02.png b/wiki/images/business_config_02.png
new file mode 100644
index 000000000..028188247
Binary files /dev/null and b/wiki/images/business_config_02.png differ
diff --git a/wiki/images/business_config_03.png b/wiki/images/business_config_03.png
new file mode 100644
index 000000000..2246e044d
Binary files /dev/null and b/wiki/images/business_config_03.png differ
diff --git a/wiki/images/business_config_04.png b/wiki/images/business_config_04.png
new file mode 100644
index 000000000..a40e5f32a
Binary files /dev/null and b/wiki/images/business_config_04.png differ