This is an automated email from the ASF dual-hosted git repository. littlecui pushed a commit to branch alarm in repository https://gitbox.apache.org/repos/asf/servicecomb-service-center.git
commit aed4a12c6b85203c2dc3874826da06f2dc5e9ed8 Author: little-cui <[email protected]> AuthorDate: Fri Nov 30 13:28:18 2018 +0800 SCB-1049 Add alarms APIs --- pkg/notify/subscriber.go | 2 +- pkg/util/{map.go => json.go} | 4 + pkg/util/{map_test.go => json_test.go} | 2 +- server/admin/controller_v4.go | 29 ++++++- server/admin/model/{cluster.go => types.go} | 16 ++++ server/admin/service.go | 66 +++++++++++++--- server/alarm/alarm.go | 51 +++---------- server/alarm/{alarm.go => center.go} | 89 ++++++++++------------ server/{admin/model/cluster.go => alarm/common.go} | 23 +++--- server/core/config.go | 2 +- server/core/swagger/v4.yaml | 75 +++++++++++++++++- server/notify/{common.go => center.go} | 8 -- server/notify/common.go | 16 +--- server/rest/controller/rest_util.go | 5 ++ 14 files changed, 246 insertions(+), 142 deletions(-) diff --git a/pkg/notify/subscriber.go b/pkg/notify/subscriber.go index 7544919..23d848c 100644 --- a/pkg/notify/subscriber.go +++ b/pkg/notify/subscriber.go @@ -35,7 +35,7 @@ type Subscriber interface { Close() OnAccept() // The event bus will callback this function, so it must be non-blocked. - OnMessage(job Event) + OnMessage(Event) } type baseSubscriber struct { diff --git a/pkg/util/map.go b/pkg/util/json.go similarity index 97% rename from pkg/util/map.go rename to pkg/util/json.go index f5d8597..7f7dbb1 100644 --- a/pkg/util/map.go +++ b/pkg/util/json.go @@ -74,3 +74,7 @@ func toString(v interface{}) string { return fmt.Sprintf("%#v", v) } } + +func NewJSONObject() JSONObject { + return make(JSONObject) +} diff --git a/pkg/util/map_test.go b/pkg/util/json_test.go similarity index 99% rename from pkg/util/map_test.go rename to pkg/util/json_test.go index 2e4affe..70f6461 100644 --- a/pkg/util/map_test.go +++ b/pkg/util/json_test.go @@ -23,7 +23,7 @@ import ( func TestNewServerInformation(t *testing.T) { var c JSONObject - c = make(JSONObject) + c = NewJSONObject() if !c.Bool("a", true) { t.Fatalf("TestNewServerInformation failed") } diff --git a/server/admin/controller_v4.go b/server/admin/controller_v4.go index 55d23e9..af620f4 100644 --- a/server/admin/controller_v4.go +++ b/server/admin/controller_v4.go @@ -22,6 +22,7 @@ import ( "github.com/apache/servicecomb-service-center/pkg/rest" "github.com/apache/servicecomb-service-center/server/admin/model" "github.com/apache/servicecomb-service-center/server/rest/controller" + "strings" ) // AdminService 治理相关接口服务 @@ -31,13 +32,22 @@ type AdminServiceControllerV4 struct { // URLPatterns 路由 func (ctrl *AdminServiceControllerV4) URLPatterns() []rest.Route { return []rest.Route{ + {rest.HTTP_METHOD_GET, "/v4/:project/admin/alarms", ctrl.AlarmList}, + {rest.HTTP_METHOD_DELETE, "/v4/:project/admin/alarms", ctrl.ClearAlarm}, {rest.HTTP_METHOD_GET, "/v4/:project/admin/dump", ctrl.Dump}, {rest.HTTP_METHOD_GET, "/v4/:project/admin/clusters", ctrl.Clusters}, } } func (ctrl *AdminServiceControllerV4) Dump(w http.ResponseWriter, r *http.Request) { - request := &model.DumpRequest{} + query := r.URL.Query() + var options []string + if s := strings.TrimSpace(query.Get("options")); len(s) > 0 { + options = strings.Split(s, ",") + } + request := &model.DumpRequest{ + Options: options, + } ctx := r.Context() resp, _ := AdminServiceAPI.Dump(ctx, request) @@ -55,3 +65,20 @@ func (ctrl *AdminServiceControllerV4) Clusters(w http.ResponseWriter, r *http.Re resp.Response = nil controller.WriteResponse(w, respInternal, resp) } + +func (ctrl *AdminServiceControllerV4) AlarmList(w http.ResponseWriter, r *http.Request) { + request := &model.AlarmListRequest{} + ctx := r.Context() + resp, _ := AdminServiceAPI.AlarmList(ctx, request) + + respInternal := resp.Response + resp.Response = nil + controller.WriteResponse(w, respInternal, resp) +} + +func (ctrl *AdminServiceControllerV4) ClearAlarm(w http.ResponseWriter, r *http.Request) { + request := &model.ClearAlarmRequest{} + ctx := r.Context() + resp, _ := AdminServiceAPI.ClearAlarm(ctx, request) + controller.WriteResponse(w, resp.Response, nil) +} diff --git a/server/admin/model/cluster.go b/server/admin/model/types.go similarity index 75% copy from server/admin/model/cluster.go copy to server/admin/model/types.go index 6cabae9..5a803ad 100644 --- a/server/admin/model/cluster.go +++ b/server/admin/model/types.go @@ -16,10 +16,19 @@ package model import ( + "github.com/apache/servicecomb-service-center/server/alarm" pb "github.com/apache/servicecomb-service-center/server/core/proto" "github.com/apache/servicecomb-service-center/server/plugin/pkg/registry" ) +type AlarmListRequest struct { +} + +type AlarmListResponse struct { + Response *pb.Response `json:"response,omitempty"` + Alarms []*alarm.AlarmEvent `json:"alarms,omitempty"` +} + type ClustersRequest struct { } @@ -27,3 +36,10 @@ type ClustersResponse struct { Response *pb.Response `json:"response,omitempty"` Clusters registry.Clusters `json:"clusters,omitempty"` } + +type ClearAlarmRequest struct { +} + +type ClearAlarmResponse struct { + Response *pb.Response `json:"response,omitempty"` +} diff --git a/server/admin/service.go b/server/admin/service.go index f6c9e7e..61d69df 100644 --- a/server/admin/service.go +++ b/server/admin/service.go @@ -18,8 +18,10 @@ package admin import ( "github.com/apache/servicecomb-service-center/pkg/gopool" + "github.com/apache/servicecomb-service-center/pkg/log" "github.com/apache/servicecomb-service-center/pkg/util" "github.com/apache/servicecomb-service-center/server/admin/model" + "github.com/apache/servicecomb-service-center/server/alarm" "github.com/apache/servicecomb-service-center/server/core" "github.com/apache/servicecomb-service-center/server/core/backend" pb "github.com/apache/servicecomb-service-center/server/core/proto" @@ -59,9 +61,7 @@ type AdminService struct { } func (service *AdminService) Dump(ctx context.Context, in *model.DumpRequest) (*model.DumpResponse, error) { - domainProject := util.ParseDomainProject(ctx) - var cache model.Cache if !core.IsDefaultDomainProject(domainProject) { return &model.DumpResponse{ @@ -69,18 +69,50 @@ func (service *AdminService) Dump(ctx context.Context, in *model.DumpRequest) (* }, nil } - service.dumpAll(ctx, &cache) + resp := &model.DumpResponse{ + Response: pb.CreateResponse(pb.Response_SUCCESS, "Admin dump successfully"), + } - return &model.DumpResponse{ - Response: pb.CreateResponse(pb.Response_SUCCESS, "Admin dump successfully"), - Info: version.Ver(), - AppConfig: configs, - Environments: environments, - Cache: &cache, - }, nil + if len(in.Options) == 0 { + service.dump(ctx, "cache", resp) + return resp, nil + } + + options := make(map[string]struct{}, len(in.Options)) + for _, option := range in.Options { + if option == "all" { + service.dump(ctx, "all", resp) + return resp, nil + } + options[option] = struct{}{} + } + for option := range options { + service.dump(ctx, option, resp) + } + return resp, nil } -func (service *AdminService) dumpAll(ctx context.Context, cache *model.Cache) { +func (service *AdminService) dump(ctx context.Context, option string, resp *model.DumpResponse) { + switch option { + case "info": + resp.Info = version.Ver() + case "config": + resp.AppConfig = configs + case "env": + resp.Environments = environments + case "cache": + var cache model.Cache + service.dumpAllCache(ctx, &cache) + resp.Cache = &cache + case "all": + service.dump(ctx, "info", resp) + service.dump(ctx, "config", resp) + service.dump(ctx, "env", resp) + service.dump(ctx, "cache", resp) + } +} + +func (service *AdminService) dumpAllCache(ctx context.Context, cache *model.Cache) { gopool.New(ctx, gopool.Configure().Workers(2)). Do(func(_ context.Context) { setValue(backend.Store().Service(), &cache.Microservices) }). Do(func(_ context.Context) { setValue(backend.Store().ServiceIndex(), &cache.Indexes) }). @@ -111,3 +143,15 @@ func (service *AdminService) Clusters(ctx context.Context, in *model.ClustersReq Clusters: registry.Configuration().Clusters, }, nil } + +func (service *AdminService) AlarmList(ctx context.Context, in *model.AlarmListRequest) (*model.AlarmListResponse, error) { + return &model.AlarmListResponse{ + Alarms: alarm.AlarmCenter().AlarmList(), + }, nil +} + +func (service *AdminService) ClearAlarm(ctx context.Context, in *model.ClearAlarmRequest) (*model.ClearAlarmResponse, error) { + alarm.AlarmCenter().Clear() + log.Infof("service center alarms are cleared") + return &model.ClearAlarmResponse{}, nil +} diff --git a/server/alarm/alarm.go b/server/alarm/alarm.go index e3639e7..c96d917 100644 --- a/server/alarm/alarm.go +++ b/server/alarm/alarm.go @@ -17,69 +17,38 @@ package alarm import ( nf "github.com/apache/servicecomb-service-center/pkg/notify" - "github.com/apache/servicecomb-service-center/server/notify" - "sync/atomic" + "github.com/apache/servicecomb-service-center/pkg/util" ) -type ID int32 - -const ( - CodeBackendConnectionRefuse ID = iota - CodeServerOverload - CodeServiceQuotaLimit - CodeInstanceQuotaLimit - CodeDiagnoseFailure - CodeInternalError - typeEnd -) - -const Subject = "__ALARM_CENTER__" - -var latestId = int32(typeEnd) +type ID string type AlarmEvent struct { - nf.Event - Id ID - fields map[string]interface{} + nf.Event `json:"-"` + Id ID `json:"id"` + Fields util.JSONObject `json:"fields,omitempty"` } func (ae *AlarmEvent) FieldBool(key string) bool { - v, _ := ae.fields[key].(bool) + v, _ := ae.Fields[key].(bool) return v } func (ae *AlarmEvent) FieldString(key string) string { - v, _ := ae.fields[key].(string) + v, _ := ae.Fields[key].(string) return v } func (ae *AlarmEvent) FieldInt64(key string) int64 { - v, _ := ae.fields[key].(int64) + v, _ := ae.Fields[key].(int64) return v } func (ae *AlarmEvent) FieldInt(key string) int { - v, _ := ae.fields[key].(int) + v, _ := ae.Fields[key].(int) return v } func (ae *AlarmEvent) FieldFloat64(key string) float64 { - v, _ := ae.fields[key].(float64) + v, _ := ae.Fields[key].(float64) return v } - -func RegisterAlarmSource() ID { - return ID(atomic.AddInt32(&latestId, 1)) -} - -func Alarm(id ID, fields ...Field) error { - ae := &AlarmEvent{ - Event: nf.NewEvent(nf.NOTIFTY, Subject, ""), - Id: id, - fields: make(map[string]interface{}, len(fields)), - } - for _, f := range fields { - ae.fields[f.Key] = f.Value - } - return notify.NotifyCenter().Publish(ae) -} diff --git a/server/alarm/alarm.go b/server/alarm/center.go similarity index 52% copy from server/alarm/alarm.go copy to server/alarm/center.go index e3639e7..d28c2c5 100644 --- a/server/alarm/alarm.go +++ b/server/alarm/center.go @@ -17,69 +17,62 @@ package alarm import ( nf "github.com/apache/servicecomb-service-center/pkg/notify" + "github.com/apache/servicecomb-service-center/pkg/util" "github.com/apache/servicecomb-service-center/server/notify" - "sync/atomic" + "sync" ) -type ID int32 - -const ( - CodeBackendConnectionRefuse ID = iota - CodeServerOverload - CodeServiceQuotaLimit - CodeInstanceQuotaLimit - CodeDiagnoseFailure - CodeInternalError - typeEnd +var ( + center *Center + once sync.Once ) -const Subject = "__ALARM_CENTER__" - -var latestId = int32(typeEnd) - -type AlarmEvent struct { - nf.Event - Id ID - fields map[string]interface{} -} - -func (ae *AlarmEvent) FieldBool(key string) bool { - v, _ := ae.fields[key].(bool) - return v +type Center struct { + nf.Subscriber + alarms util.ConcurrentMap } -func (ae *AlarmEvent) FieldString(key string) string { - v, _ := ae.fields[key].(string) - return v +func (ac *Center) Alarm(id ID, fields ...Field) error { + ae := &AlarmEvent{ + Event: nf.NewEvent(nf.NOTIFTY, Subject, ""), + Id: id, + Fields: util.NewJSONObject(), + } + for _, f := range fields { + ae.Fields[f.Key] = f.Value + } + return notify.NotifyCenter().Publish(ae) } -func (ae *AlarmEvent) FieldInt64(key string) int64 { - v, _ := ae.fields[key].(int64) - return v +func (ac *Center) AlarmList() (ls []*AlarmEvent) { + ac.alarms.ForEach(func(item util.MapItem) (next bool) { + ls = append(ls, item.Value.(*AlarmEvent)) + return true + }) + return } -func (ae *AlarmEvent) FieldInt(key string) int { - v, _ := ae.fields[key].(int) - return v +func (ac *Center) Clear() { + ac.alarms = util.ConcurrentMap{} + return } -func (ae *AlarmEvent) FieldFloat64(key string) float64 { - v, _ := ae.fields[key].(float64) - return v +func (ac *Center) OnMessage(evt nf.Event) { + alarm := evt.(*AlarmEvent) + ac.alarms.Put(alarm.Id, alarm) } -func RegisterAlarmSource() ID { - return ID(atomic.AddInt32(&latestId, 1)) +func NewAlarmCenter() *Center { + c := &Center{ + Subscriber: nf.NewSubscriber(nf.NOTIFTY, Subject, Group), + } + notify.NotifyCenter().AddSubscriber(c) + return c } -func Alarm(id ID, fields ...Field) error { - ae := &AlarmEvent{ - Event: nf.NewEvent(nf.NOTIFTY, Subject, ""), - Id: id, - fields: make(map[string]interface{}, len(fields)), - } - for _, f := range fields { - ae.fields[f.Key] = f.Value - } - return notify.NotifyCenter().Publish(ae) +func AlarmCenter() *Center { + once.Do(func() { + center = NewAlarmCenter() + }) + return center } diff --git a/server/admin/model/cluster.go b/server/alarm/common.go similarity index 67% rename from server/admin/model/cluster.go rename to server/alarm/common.go index 6cabae9..ab95b98 100644 --- a/server/admin/model/cluster.go +++ b/server/alarm/common.go @@ -13,17 +13,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -package model +package alarm -import ( - pb "github.com/apache/servicecomb-service-center/server/core/proto" - "github.com/apache/servicecomb-service-center/server/plugin/pkg/registry" +const ( + BackendConnectionRefuse ID = "BackendConnectionRefuse" + ServerOverload ID = "ServerOverload" + ServiceQuotaLimit ID = "ServiceQuotaLimit" + InstanceQuotaLimit ID = "InstanceQuotaLimit" + DiagnoseFailure ID = "DiagnoseFailure" + InternalError ID = "InternalError" ) -type ClustersRequest struct { -} - -type ClustersResponse struct { - Response *pb.Response `json:"response,omitempty"` - Clusters registry.Clusters `json:"clusters,omitempty"` -} +const ( + Subject = "__ALARM_SUBJECT__" + Group = "__ALARM_GROUP__" +) diff --git a/server/core/config.go b/server/core/config.go index c95224d..ab2f891 100644 --- a/server/core/config.go +++ b/server/core/config.go @@ -87,7 +87,7 @@ func newInfo() pb.ServerInformation { LogSys: beego.AppConfig.DefaultBool("log_sys", false), PluginsDir: beego.AppConfig.DefaultString("plugins_dir", "./plugins"), - Plugins: make(util.JSONObject), + Plugins: util.NewJSONObject(), EnablePProf: beego.AppConfig.DefaultInt("enable_pprof", 0) != 0, EnableCache: beego.AppConfig.DefaultInt("enable_cache", 1) != 0, diff --git a/server/core/swagger/v4.yaml b/server/core/swagger/v4.yaml index 7d3aaef..06f071a 100644 --- a/server/core/swagger/v4.yaml +++ b/server/core/swagger/v4.yaml @@ -1533,7 +1533,7 @@ paths: get: description: | 查询单个服务的所有信息。 - operationId: GetServiceDetail + operationId: getServiceDetail parameters: - name: x-domain-name in: header @@ -1568,7 +1568,7 @@ paths: get: description: | 查询单个服务的所有信息。 - operationId: GetServicesInfo + operationId: getServicesInfo parameters: - name: x-domain-name in: header @@ -1603,7 +1603,7 @@ paths: get: description: | 查询服务间的关系。 - operationId: GetGraph + operationId: getGraph parameters: - name: x-domain-name in: header @@ -1635,7 +1635,7 @@ paths: get: description: | 查询所有appId。 - operationId: GetApplications + operationId: getApplications parameters: - name: x-domain-name in: header @@ -1685,6 +1685,11 @@ paths: description: default项目 required: true type: string + - name: options + in: query + default: cache + description: 枚举值有:info,config,env,cache和all + type: string tags: - admin responses: @@ -1721,6 +1726,53 @@ paths: description: clusters information schema: $ref: '#/definitions/ClustersResponse' + /v4/{project}/admin/alarms: + get: + description: | + Return the alarms list of Service Center + operationId: alarmList + parameters: + - name: x-domain-name + in: header + type: string + default: default + description: default租户 + required: true + - name: project + in: path + default: default + description: default项目 + required: true + type: string + tags: + - admin + responses: + 200: + description: alarms information + schema: + $ref: '#/definitions/AlarmList' + delete: + description: | + Clear the alarms list of Service Center + operationId: clearAlarm + parameters: + - name: x-domain-name + in: header + type: string + default: default + description: default租户 + required: true + - name: project + in: path + default: default + description: default项目 + required: true + type: string + tags: + - admin + responses: + 200: + description: cleared definitions: Version: type: object @@ -2552,3 +2604,18 @@ definitions: type: string detail: type: string + AlarmList: + type: object + description: alarms information + additionalProperties: + type: array + items: + $ref: '#/definitions/Alarm' + Alarm: + type: object + description: alarm information + properties: + id: + type: string + fields: + $ref: '#/definitions/Properties' diff --git a/server/notify/common.go b/server/notify/center.go similarity index 86% copy from server/notify/common.go copy to server/notify/center.go index b130cb1..db95ec3 100644 --- a/server/notify/common.go +++ b/server/notify/center.go @@ -17,14 +17,6 @@ package notify import ( "github.com/apache/servicecomb-service-center/pkg/notify" - "time" -) - -const ( - AddJobTimeout = 1 * time.Second - SendTimeout = 5 * time.Second - HeartbeatTimeout = 30 * time.Second - InstanceEventQueueSize = 5000 ) var INSTANCE = notify.RegisterType("INSTANCE", InstanceEventQueueSize) diff --git a/server/notify/common.go b/server/notify/common.go index b130cb1..e3c9a67 100644 --- a/server/notify/common.go +++ b/server/notify/common.go @@ -15,10 +15,7 @@ package notify -import ( - "github.com/apache/servicecomb-service-center/pkg/notify" - "time" -) +import "time" const ( AddJobTimeout = 1 * time.Second @@ -26,14 +23,3 @@ const ( HeartbeatTimeout = 30 * time.Second InstanceEventQueueSize = 5000 ) - -var INSTANCE = notify.RegisterType("INSTANCE", InstanceEventQueueSize) -var notifyService *notify.NotifyService - -func init() { - notifyService = notify.NewNotifyService() -} - -func NotifyCenter() *notify.NotifyService { - return notifyService -} diff --git a/server/rest/controller/rest_util.go b/server/rest/controller/rest_util.go index ca75b1f..b603e41 100644 --- a/server/rest/controller/rest_util.go +++ b/server/rest/controller/rest_util.go @@ -21,6 +21,7 @@ import ( "fmt" "github.com/apache/servicecomb-service-center/pkg/rest" "github.com/apache/servicecomb-service-center/pkg/util" + "github.com/apache/servicecomb-service-center/server/alarm" pb "github.com/apache/servicecomb-service-center/server/core/proto" "github.com/apache/servicecomb-service-center/server/error" "net/http" @@ -33,6 +34,10 @@ func WriteError(w http.ResponseWriter, code int32, detail string) { w.Header().Set(rest.HEADER_CONTENT_TYPE, rest.CONTENT_TYPE_JSON) w.WriteHeader(err.StatusCode()) fmt.Fprintln(w, util.BytesToStringWithNoCopy(err.Marshal())) + + if err.InternalError() { + alarm.AlarmCenter().Alarm(alarm.InternalError, alarm.FieldString("detail", detail)) + } } func WriteResponse(w http.ResponseWriter, resp *pb.Response, obj interface{}) {
