diff --git a/OWNERS b/OWNERS new file mode 100644 index 0000000..b7f9e80 --- /dev/null +++ b/OWNERS @@ -0,0 +1,2 @@ +approvers: +- liu-song \ No newline at end of file diff --git a/README.md b/README.md index a46ae92..0b86125 100644 --- a/README.md +++ b/README.md @@ -1 +1,48 @@ -# .github \ No newline at end of file +## shmipc-prometheus is a Prometheus monitoring for [shmipc-go](https://github.com/cloudwego/shmipc-go) (*This is a community driven project*) + +## How to use with shmipc-go server? + +**[example/shmipc_server/main.go](example/shmipc_server/main.go)** + +```go +package main + +import ( + shmipcprometheus "github.com/cloudwego-contrib/shmipc-prometheus" + "github.com/cloudwego/shmipc-go" +) + +func main() { + ... + conf := shmipc.DefaultSessionManagerConfig() + conf.Monitor = shmipcprometheus.NewPrometheusMonitor(":9094", "/metrics") + smgr, _ := shmipc.NewSessionManager(conf) + ... +} +``` + +## How to use with shmipc-go client? + +**[example/shmipc_client/main.go](example/shmipc_client/main.go)** + +```go +package main + +import ( + shmipcprometheus "github.com/cloudwego-contrib/shmipc-prometheus" + "github.com/cloudwego/shmipc-go" +) + +func main() { + ... + conf := shmipc.DefaultConfig() + conf.Monitor = shmipcprometheus.NewPrometheusMonitor(":9095", "/metrics") + server, err := shmipc.Server(conn, conf) + ... +} +``` + +## example + +**[example for shmipc-prometheus](example)** + diff --git a/example/README.md b/example/README.md new file mode 100644 index 0000000..aa2e7af --- /dev/null +++ b/example/README.md @@ -0,0 +1,37 @@ +# Prometheus monitoring for shmipc-go + +## Usage Example + +### Server + +See [server](./shmipc_server) + +### Client + +See [client](./shmipc_client) + +## HOW-TO-RUN + +1. install docker and start docker +2. change `{{ INET_IP }}` to local ip in prometheus.yml +3. run Prometheus and Grafana + `docker-compose up` +4. run shmipc_client and shmipc_server + `sh run_shmipc_client_server.sh` +5. visit `http://localhost:3000`, the account password is `admin` by default +6. configure Prometheus data sources + 1. `Configuration` + 2. `Data Source` + 3. `Add data source` + 4. Select `Prometheus` and fill the URL with `http://prometheus:9090` + 5. click `Save & Test` after configuration to test if it works +7. add dashboard `Create` -> `dashboard`, add monitoring metrics such as shmipc-client all in used share memory in bytes and shmipc-server active stream count according to your needs, + for example: + + - shmipc-client all in used share memory in bytes + + `all_in_used_share_memory_in_bytes{job="shmipc-client"}` + + - shmipc-server active stream count + + `active_stream_count{job="shmipc-server"}` diff --git a/example/docker-compose.yaml b/example/docker-compose.yaml new file mode 100644 index 0000000..a8f8053 --- /dev/null +++ b/example/docker-compose.yaml @@ -0,0 +1,25 @@ +version: "2" +services: + prometheus: + image: prom/prometheus:latest + volumes: + - ./prometheus.yml:/etc/prometheus/prometheus.yml + # - ./alert.rules:/etc/prometheus/alert.rules + - prometheus_data:/prometheus + command: + - "--config.file=/etc/prometheus/prometheus.yml" + ports: + - "9090:9090" + grafana: + image: grafana/grafana:latest + volumes: + - grafana_data:/var/lib/grafana + environment: + - GF_SECURITY_ADMIN_PASSWORD=admin + depends_on: + - prometheus + ports: + - "3000:3000" +volumes: + grafana_data: { } + prometheus_data: { } diff --git a/example/prometheus.yml b/example/prometheus.yml new file mode 100644 index 0000000..5b62970 --- /dev/null +++ b/example/prometheus.yml @@ -0,0 +1,37 @@ +# my global config +global: + scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute. + evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute. + # scrape_timeout is set to the global default (10s). + +# Alertmanager configuration +alerting: + alertmanagers: + - static_configs: + - targets: + # - alertmanager:9093 + +# Load rules once and periodically evaluate them according to the global 'evaluation_interval'. +rule_files: +# - "first_rules.yml" +# - "second_rules.yml" + +# A scrape configuration containing exactly one endpoint to scrape: +# Here it's Prometheus itself. +scrape_configs: + # The job name is added as a label `job=` to any timeseries scraped from this config. + - job_name: "shmipc-server" + + # metrics_path defaults to '/metrics' + # scheme defaults to 'http'. + + scrape_interval: 1s + static_configs: + - targets: [ "{{ INET_IP }}:9095" ] + + - job_name: "shmipc-client" + + scrape_interval: 1s + static_configs: + - targets: [ "{{ INET_IP }}:9094" ] + diff --git a/example/run_shmipc_client_server.sh b/example/run_shmipc_client_server.sh new file mode 100755 index 0000000..baa40bb --- /dev/null +++ b/example/run_shmipc_client_server.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +cd shmipc_server +go build +cd ../shmipc_client +go build + +cd ../shmipc_server +./shmipc_server & +SERVER_PID=$! +echo "server pid is $SERVER_PID" +sleep 1s + +cd ../shmipc_client +./shmipc_client & +CLIENT_PID=$! +echo "client pid is $CLIENT_PID" + +trap 'echo "exiting, now kill client and server";kill $CLIENT_PID;kill $SERVER_PID' SIGHUP SIGINT SIGQUIT SIGALRM SIGTERM +cd ../ + +sleep 1000s diff --git a/example/shmipc_client/main.go b/example/shmipc_client/main.go new file mode 100644 index 0000000..efd3f11 --- /dev/null +++ b/example/shmipc_client/main.go @@ -0,0 +1,131 @@ +/* + * Copyright 2023 CloudWeGo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package main + +import ( + "flag" + "fmt" + "math/rand" + "net/http" + _ "net/http/pprof" + "os" + "path/filepath" + "runtime" + "sync/atomic" + "time" + + shmipcprometheus "github.com/cloudwego-contrib/shmipc-prometheus" + "github.com/cloudwego/shmipc-go" + "github.com/cloudwego/shmipc-go/example/best_practice/idl" +) + +var count uint64 + +func init() { + go func() { + lastCount := count + for range time.Tick(time.Second) { + curCount := atomic.LoadUint64(&count) + fmt.Println("shmipc_client qps:", curCount-lastCount) + lastCount = curCount + } + }() + + go func() { + http.ListenAndServe(":20001", nil) //nolint:errcheck + }() + + runtime.GOMAXPROCS(1) +} + +func main() { + packageSize := flag.Int("p", 1024, "-p 1024 mean that request and response's size are both near 1KB") + flag.Parse() + + randContent := make([]byte, *packageSize) + rand.Read(randContent) + + // 1. get current directory + dir, err := os.Getwd() + if err != nil { + panic(err) + } + + // 2. init session manager + conf := shmipc.DefaultSessionManagerConfig() + conf.Address = filepath.Join(dir, "../ipc_test.sock") + conf.Network = "unix" + conf.MemMapType = shmipc.MemMapTypeMemFd + conf.SessionNum = 1 + conf.InitializeTimeout = 100 * time.Second + conf.Monitor = shmipcprometheus.NewPrometheusMonitor(":9094", "/metrics") + smgr, err := shmipc.NewSessionManager(conf) + if err != nil { + panic(err) + } + + concurrency := 500 + qps := 50000000 + + for i := 0; i < concurrency; i++ { + go func() { + req := &idl.Request{} + resp := &idl.Response{} + n := qps / concurrency + + for range time.Tick(time.Second) { + // 3. get stream from SessionManager + stream, err := smgr.GetStream() + if err != nil { + fmt.Println("get stream error:" + err.Error()) + continue + } + + for k := 0; k < n; k++ { + // 4. set request object + req.Reset() + req.ID = uint64(time.Now().UnixNano()) + req.Name = "xxx" + req.Key = randContent + + // 5. write req to buffer of stream + if err := req.WriteToShm(stream.BufferWriter()); err != nil { + fmt.Println("write request to share memory failed, err=" + err.Error()) + return + } + + // 6. flush the buffered data of stream to peer + if err := stream.Flush(false); err != nil { + fmt.Println(" flush request to peer failed, err=" + err.Error()) + return + } + + // 7. wait and read response + resp.Reset() + if err := resp.ReadFromShm(stream.BufferReader()); err != nil { + fmt.Println("write request to share memory failed, err=" + err.Error()) + continue + } + + atomic.AddUint64(&count, 1) + } + } + }() + } + + time.Sleep(1200 * time.Second) +} diff --git a/example/shmipc_server/main.go b/example/shmipc_server/main.go new file mode 100644 index 0000000..576c1b8 --- /dev/null +++ b/example/shmipc_server/main.go @@ -0,0 +1,130 @@ +/* + * Copyright 2023 CloudWeGo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package main + +import ( + "fmt" + "net" + "net/http" + _ "net/http/pprof" + "os" + "path/filepath" + "runtime" + "sync/atomic" + "syscall" + "time" + + shmipcprometheus "github.com/cloudwego-contrib/shmipc-prometheus" + "github.com/cloudwego/shmipc-go" + "github.com/cloudwego/shmipc-go/example/best_practice/idl" +) + +var count uint64 + +func handleStream(s *shmipc.Stream) { + req := &idl.Request{} + resp := &idl.Response{} + for { + // 1. deserialize Request + if err := req.ReadFromShm(s.BufferReader()); err != nil { + fmt.Println("stream read request, err=" + err.Error()) + return + } + + { + // 2. handle request + atomic.AddUint64(&count, 1) + } + + // 3.serialize Response + resp.ID = req.ID + resp.Name = req.Name + resp.Image = req.Key + if err := resp.WriteToShm(s.BufferWriter()); err != nil { + fmt.Println("stream write response failed, err=" + err.Error()) + return + } + if err := s.Flush(false); err != nil { + fmt.Println("stream write response failed, err=" + err.Error()) + return + } + req.Reset() + resp.Reset() + } +} + +func init() { + go func() { + lastCount := count + for range time.Tick(time.Second) { + curCount := atomic.LoadUint64(&count) + fmt.Println("shmipc_server qps:", curCount-lastCount) + lastCount = curCount + } + }() + go func() { + http.ListenAndServe(":20000", nil) //nolint:errcheck + }() + runtime.GOMAXPROCS(1) +} + +func main() { + dir, err := os.Getwd() + if err != nil { + panic(err) + } + udsPath := filepath.Join(dir, "../ipc_test.sock") + + // 1. listen unix domain socket + _ = syscall.Unlink(udsPath) + ln, err := net.ListenUnix("unix", &net.UnixAddr{Name: udsPath, Net: "unix"}) + if err != nil { + panic(err) + } + defer ln.Close() + + // 2. accept a unix domain socket + for { + conn, err := ln.Accept() + if err != nil { + fmt.Printf("accept error:%s now exit", err.Error()) + return + } + go func() { + defer conn.Close() + + // 3. create server session + conf := shmipc.DefaultConfig() + conf.Monitor = shmipcprometheus.NewPrometheusMonitor(":9095", "/metrics") + server, err := shmipc.Server(conn, conf) + if err != nil { + panic("new ipc server failed " + err.Error()) + } + defer server.Close() + + // 4. accept stream and handle + for { + stream, err := server.AcceptStream() + if err != nil { + fmt.Println("shmipc server accept stream failed, err=" + err.Error()) + break + } + go handleStream(stream) + } + }() + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..f7af53e --- /dev/null +++ b/go.mod @@ -0,0 +1,30 @@ +module github.com/cloudwego-contrib/shmipc-prometheus + +go 1.20 + +require ( + github.com/cloudwego/shmipc-go v0.1.0 + github.com/prometheus/client_golang v1.16.0 + github.com/stretchr/testify v1.8.2 +) + +require ( + github.com/beorn7/perks v1.0.1 // indirect + github.com/bytedance/gopkg v0.0.0-20220817015305-b879a72dc90f // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect + github.com/prometheus/client_model v0.3.0 // indirect + github.com/prometheus/common v0.42.0 // indirect + github.com/prometheus/procfs v0.10.1 // indirect + github.com/rogpeppe/go-internal v1.10.0 // indirect + github.com/shirou/gopsutil/v3 v3.22.1 // indirect + github.com/yusufpapurcu/wmi v1.2.2 // indirect + golang.org/x/sys v0.8.0 // indirect + google.golang.org/protobuf v1.30.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..cd0d69d --- /dev/null +++ b/go.sum @@ -0,0 +1,79 @@ +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bytedance/gopkg v0.0.0-20220817015305-b879a72dc90f h1:U3Bk6S9UyqFM5tU3bZ3pwqx5xyypHP7Bm2QCbOUwxSc= +github.com/bytedance/gopkg v0.0.0-20220817015305-b879a72dc90f/go.mod h1:2ZlV9BaUH4+NXIBF0aMdKKAnHTzqH+iMU4KUjAbL23Q= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cloudwego/shmipc-go v0.1.0 h1:xWU784onsQnoNKbIhGnxoa5AomFDNvsSdhRJtUWfa5A= +github.com/cloudwego/shmipc-go v0.1.0/go.mod h1:GC7vRhqQoFUojoBq3lDsuJCYDtbEmoDPLdXBHqGCQAQ= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= +github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= +github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= +github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= +github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/shirou/gopsutil/v3 v3.22.1 h1:33y31Q8J32+KstqPfscvFwBlNJ6xLaBy4xqBXzlYV5w= +github.com/shirou/gopsutil/v3 v3.22.1/go.mod h1:WapW1AOOPlHyXr+yOyw3uYx36enocrtSoSBy0L5vUHY= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs= +github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8= +github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= +github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220110181412-a018aaa089fe/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/licenses/LICENSE-prometheus b/licenses/LICENSE-prometheus new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/licenses/LICENSE-prometheus @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/licenses/LICENSE-testify b/licenses/LICENSE-testify new file mode 100644 index 0000000..4b0421c --- /dev/null +++ b/licenses/LICENSE-testify @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2012-2020 Mat Ryer, Tyler Bunnell and contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/monitor.go b/monitor.go new file mode 100644 index 0000000..0fe2a27 --- /dev/null +++ b/monitor.go @@ -0,0 +1,224 @@ +/* + * Copyright 2023 CloudWeGo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shmipc + +import ( + "fmt" + "log" + "net/http" + "os" + "time" + + "github.com/cloudwego/shmipc-go" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/prometheus/client_golang/prometheus/promhttp" +) + +type PrometheusMonitor struct { + receiveSyncEventCount prometheus.Gauge + sendSyncEventCount prometheus.Gauge + outFlowBytes prometheus.Gauge + inFlowBytes prometheus.Gauge + sendQueueCount prometheus.Gauge + receiveQueueCount prometheus.Gauge + + allocShmErrorCount prometheus.Gauge + fallbackWriteCount prometheus.Gauge + fallbackReadCount prometheus.Gauge + eventConnErrorCount prometheus.Gauge + queueFullErrorCount prometheus.Gauge + activeStreamCount prometheus.Gauge + hotRestartSuccessCount prometheus.Gauge + hotRestartErrorCount prometheus.Gauge + + capacityOfShareMemory prometheus.Gauge + allInUsedShareMemory prometheus.Gauge + + MonitorInfo map[string]float64 +} + +func NewPrometheusMonitor(addr, path string) *PrometheusMonitor { + registry := prometheus.NewRegistry() + + http.Handle(path, promhttp.HandlerFor(registry, promhttp.HandlerOpts{ErrorHandling: promhttp.ContinueOnError})) + go func() { + if err := http.ListenAndServe(addr, nil); err != nil { + log.Fatal("Unable to start a promhttp server, err: " + err.Error()) + } + }() + + receiveSyncEventCount := promauto.NewGauge(prometheus.GaugeOpts{ + Name: "receive_sync_event_count", + Help: "The SyncEvent count that session had received", + }) + sendSyncEventCount := promauto.NewGauge(prometheus.GaugeOpts{ + Name: "send_sync_event_count", + Help: "The SyncEvent count that session had sent", + }) + outFlowBytes := promauto.NewGauge(prometheus.GaugeOpts{ + Name: "out_flow_bytes", + Help: "The out flow in bytes that session had sent", + }) + inFlowBytes := promauto.NewGauge(prometheus.GaugeOpts{ + Name: "in_flow_bytes", + Help: "The in flow in bytes that session had receive", + }) + sendQueueCount := promauto.NewGauge(prometheus.GaugeOpts{ + Name: "send_queue_count", + Help: "The pending count of send queue", + }) + receiveQueueCount := promauto.NewGauge(prometheus.GaugeOpts{ + Name: "receive_queue_count", + Help: "The pending count of receive queue", + }) + allocShmErrorCount := promauto.NewGauge(prometheus.GaugeOpts{ + Name: "alloc_shm_error_count", + Help: "The error count of allocating share memory", + }) + fallbackWriteCount := promauto.NewGauge(prometheus.GaugeOpts{ + Name: "fallback_write_count", + Help: "The count of the fallback data write to unix/tcp connection", + }) + fallbackReadCount := promauto.NewGauge(prometheus.GaugeOpts{ + Name: "fallback_read_count", + Help: "The error count of receiving fallback data from unix/tcp connection every period", + }) + eventConnErrorCount := promauto.NewGauge(prometheus.GaugeOpts{ + Name: "event_conn_error_count", + Help: "The error count of unix/tcp connection which usually happened in that the peer's process exit(crashed or other reason)", + }) + queueFullErrorCount := promauto.NewGauge(prometheus.GaugeOpts{ + Name: "queue_full_error_count", + Help: "The error count due to the IO-Queue(SendQueue or ReceiveQueue) is full which usually happened in that the peer was busy", + }) + activeStreamCount := promauto.NewGauge(prometheus.GaugeOpts{ + Name: "active_stream_count", + Help: "Current all active stream count", + }) + hotRestartSuccessCount := promauto.NewGauge(prometheus.GaugeOpts{ + Name: "hot_restart_success_count", + Help: "The successful count of hot restart", + }) + hotRestartErrorCount := promauto.NewGauge(prometheus.GaugeOpts{ + Name: "hot_restart_error_count", + Help: "The failed count of hot restart", + }) + capacityOfShareMemory := promauto.NewGauge(prometheus.GaugeOpts{ + Name: "capacity_of_share_memory", + Help: "The capacity of the share memory in bytes", + }) + allInUsedShareMemory := promauto.NewGauge(prometheus.GaugeOpts{ + Name: "all_in_used_share_memory", + Help: "The amount of share memory in bytes that is currently in use", + }) + + registry.MustRegister( + receiveSyncEventCount, + sendSyncEventCount, + outFlowBytes, + inFlowBytes, + sendQueueCount, + receiveQueueCount, + allocShmErrorCount, + fallbackWriteCount, + fallbackReadCount, + eventConnErrorCount, + queueFullErrorCount, + activeStreamCount, + hotRestartSuccessCount, + hotRestartErrorCount, + capacityOfShareMemory, + allInUsedShareMemory, + ) + + return &PrometheusMonitor{ + receiveSyncEventCount: receiveSyncEventCount, + sendSyncEventCount: sendSyncEventCount, + outFlowBytes: outFlowBytes, + inFlowBytes: inFlowBytes, + sendQueueCount: sendQueueCount, + receiveQueueCount: receiveQueueCount, + allocShmErrorCount: allocShmErrorCount, + fallbackWriteCount: fallbackWriteCount, + fallbackReadCount: fallbackReadCount, + eventConnErrorCount: eventConnErrorCount, + queueFullErrorCount: queueFullErrorCount, + activeStreamCount: activeStreamCount, + hotRestartSuccessCount: hotRestartSuccessCount, + hotRestartErrorCount: hotRestartErrorCount, + capacityOfShareMemory: capacityOfShareMemory, + allInUsedShareMemory: allInUsedShareMemory, + MonitorInfo: make(map[string]float64), + } +} + +// OnEmitSessionMetrics was called by shmipc-go Session with periodically. +func (p *PrometheusMonitor) OnEmitSessionMetrics(performanceMetrics shmipc.PerformanceMetrics, stabilityMetrics shmipc.StabilityMetrics, shareMemoryMetrics shmipc.ShareMemoryMetrics, session *shmipc.Session) { + p.receiveSyncEventCount.Set(float64(performanceMetrics.ReceiveSyncEventCount)) + p.sendSyncEventCount.Set(float64(performanceMetrics.SendSyncEventCount)) + p.outFlowBytes.Set(float64(performanceMetrics.OutFlowBytes)) + p.inFlowBytes.Set(float64(performanceMetrics.InFlowBytes)) + p.sendQueueCount.Set(float64(performanceMetrics.SendQueueCount)) + p.receiveQueueCount.Set(float64(performanceMetrics.ReceiveQueueCount)) + + p.allocShmErrorCount.Set(float64(stabilityMetrics.AllocShmErrorCount)) + p.fallbackWriteCount.Set(float64(stabilityMetrics.FallbackWriteCount)) + p.fallbackReadCount.Set(float64(stabilityMetrics.FallbackReadCount)) + p.eventConnErrorCount.Set(float64(stabilityMetrics.EventConnErrorCount)) + p.queueFullErrorCount.Set(float64(stabilityMetrics.QueueFullErrorCount)) + p.activeStreamCount.Set(float64(stabilityMetrics.ActiveStreamCount)) + p.hotRestartSuccessCount.Set(float64(stabilityMetrics.HotRestartSuccessCount)) + p.hotRestartErrorCount.Set(float64(stabilityMetrics.HotRestartErrorCount)) + + p.capacityOfShareMemory.Set(float64(shareMemoryMetrics.CapacityOfShareMemoryInBytes)) + p.allInUsedShareMemory.Set(float64(shareMemoryMetrics.AllInUsedShareMemoryInBytes)) + + p.MonitorInfo["receiveSyncEventCount"] = float64(performanceMetrics.ReceiveSyncEventCount) + p.MonitorInfo["sendSyncEventCount"] = float64(performanceMetrics.SendSyncEventCount) + p.MonitorInfo["outFlowBytes"] = float64(performanceMetrics.OutFlowBytes) + p.MonitorInfo["inFlowBytes"] = float64(performanceMetrics.InFlowBytes) + p.MonitorInfo["sendQueueCount"] = float64(performanceMetrics.SendQueueCount) + p.MonitorInfo["receiveQueueCount"] = float64(performanceMetrics.ReceiveQueueCount) + + p.MonitorInfo["allocShmErrorCount"] = float64(stabilityMetrics.AllocShmErrorCount) + p.MonitorInfo["fallbackWriteCount"] = float64(stabilityMetrics.FallbackWriteCount) + p.MonitorInfo["fallbackReadCount"] = float64(stabilityMetrics.FallbackReadCount) + p.MonitorInfo["eventConnErrorCount"] = float64(stabilityMetrics.EventConnErrorCount) + p.MonitorInfo["queueFullErrorCount"] = float64(stabilityMetrics.QueueFullErrorCount) + p.MonitorInfo["activeStreamCount"] = float64(stabilityMetrics.ActiveStreamCount) + p.MonitorInfo["hotRestartSuccessCount"] = float64(stabilityMetrics.HotRestartSuccessCount) + p.MonitorInfo["hotRestartErrorCount"] = float64(stabilityMetrics.HotRestartErrorCount) + + p.MonitorInfo["capacityOfShareMemory"] = float64(shareMemoryMetrics.CapacityOfShareMemoryInBytes) + p.MonitorInfo["allInUsedShareMemory"] = float64(shareMemoryMetrics.AllInUsedShareMemoryInBytes) +} + +// Flush metrics to log file +func (p *PrometheusMonitor) Flush() error { + f, err := os.Create(fmt.Sprintf("MonitorInfo_%s.log", time.Now().Format("20060102150405"))) + if err != nil { + return fmt.Errorf("failed to create file: %s", err) + } + defer f.Close() + + for key, value := range p.MonitorInfo { + fmt.Fprintf(f, "%s: %f\n", key, value) + } + + return nil +} diff --git a/monitor_test.go b/monitor_test.go new file mode 100644 index 0000000..ddf693f --- /dev/null +++ b/monitor_test.go @@ -0,0 +1,102 @@ +/* + * Copyright 2023 CloudWeGo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shmipc + +import ( + "testing" + + "github.com/cloudwego/shmipc-go" + "github.com/stretchr/testify/assert" +) + +func TestNewPrometheusMonitor(t *testing.T) { + addr := "localhost:9090" + path := "/metrics" + monitor := NewPrometheusMonitor(addr, path) + + assert.NotNil(t, monitor.receiveSyncEventCount) + assert.NotNil(t, monitor.sendSyncEventCount) + assert.NotNil(t, monitor.outFlowBytes) + assert.NotNil(t, monitor.inFlowBytes) + assert.NotNil(t, monitor.sendQueueCount) + assert.NotNil(t, monitor.receiveQueueCount) + assert.NotNil(t, monitor.allocShmErrorCount) + assert.NotNil(t, monitor.fallbackWriteCount) + assert.NotNil(t, monitor.fallbackReadCount) + assert.NotNil(t, monitor.eventConnErrorCount) + assert.NotNil(t, monitor.queueFullErrorCount) + assert.NotNil(t, monitor.activeStreamCount) + assert.NotNil(t, monitor.hotRestartSuccessCount) + assert.NotNil(t, monitor.hotRestartErrorCount) + assert.NotNil(t, monitor.capacityOfShareMemory) + assert.NotNil(t, monitor.allInUsedShareMemory) + assert.NotNil(t, monitor.MonitorInfo) +} + +func TestOnEmitSessionMetricsAndFlush(t *testing.T) { + addr := "localhost:9090" + path := "/metrics" + monitor := NewPrometheusMonitor(addr, path) + + performanceMetrics := shmipc.PerformanceMetrics{ + ReceiveSyncEventCount: 10, + SendSyncEventCount: 20, + OutFlowBytes: 30, + InFlowBytes: 40, + SendQueueCount: 50, + ReceiveQueueCount: 60, + } + + stabilityMetrics := shmipc.StabilityMetrics{ + AllocShmErrorCount: 1, + FallbackWriteCount: 2, + FallbackReadCount: 3, + EventConnErrorCount: 4, + QueueFullErrorCount: 5, + ActiveStreamCount: 6, + HotRestartSuccessCount: 7, + HotRestartErrorCount: 8, + } + + shareMemoryMetrics := shmipc.ShareMemoryMetrics{ + CapacityOfShareMemoryInBytes: 1024 * 1024, + AllInUsedShareMemoryInBytes: 512 * 1024, + } + + monitor.OnEmitSessionMetrics(performanceMetrics, stabilityMetrics, shareMemoryMetrics, nil) + + assert.Equal(t, float64(10), monitor.MonitorInfo["receiveSyncEventCount"]) + assert.Equal(t, float64(20), monitor.MonitorInfo["sendSyncEventCount"]) + assert.Equal(t, float64(30), monitor.MonitorInfo["outFlowBytes"]) + assert.Equal(t, float64(40), monitor.MonitorInfo["inFlowBytes"]) + assert.Equal(t, float64(50), monitor.MonitorInfo["sendQueueCount"]) + assert.Equal(t, float64(60), monitor.MonitorInfo["receiveQueueCount"]) + assert.Equal(t, float64(1), monitor.MonitorInfo["allocShmErrorCount"]) + assert.Equal(t, float64(2), monitor.MonitorInfo["fallbackWriteCount"]) + assert.Equal(t, float64(3), monitor.MonitorInfo["fallbackReadCount"]) + assert.Equal(t, float64(4), monitor.MonitorInfo["eventConnErrorCount"]) + assert.Equal(t, float64(5), monitor.MonitorInfo["queueFullErrorCount"]) + assert.Equal(t, float64(6), monitor.MonitorInfo["activeStreamCount"]) + assert.Equal(t, float64(7), monitor.MonitorInfo["hotRestartSuccessCount"]) + assert.Equal(t, float64(8), monitor.MonitorInfo["hotRestartErrorCount"]) + assert.Equal(t, float64(1024*1024), monitor.MonitorInfo["capacityOfShareMemory"]) + assert.Equal(t, float64(512*1024), monitor.MonitorInfo["allInUsedShareMemory"]) + + // flush the metrics to the Prometheus server + err := monitor.Flush() + assert.Nil(t, err) +} diff --git a/profile/README.md b/profile/README.md index 2127160..7438ec1 100644 --- a/profile/README.md +++ b/profile/README.md @@ -8,6 +8,6 @@ 🍿 Security - [Vulnerability Reporting](https://www.cloudwego.io/zh/security/vulnerability-reporting/), [Safety Bulletin](https://www.cloudwego.io/zh/security/safety-bulletin/) -🌲 Ecosystem - [Kitex-contrib](https://github.com/kitex-contrib), [Hertz-contrib](https://github.com/hertz-contrib), [Volo-rs](https://github.com/volo-rs) +🌲 Ecosystem - [Kitex-contrib](https://github.com/kitex-contrib), [Hertz-contrib](https://github.com/hertz-contrib), [Volo-rs](https://github.com/volo-rs),[cloudwego-contrib](https://github.com/cloudwego-contrib) 🎊 Example - [kitex-example](https://github.com/cloudwego/kitex-examples), [hertz-example](https://github.com/cloudwego/hertz-examples), [biz-demo](https://github.com/cloudwego/biz-demo), [netpoll-example](https://github.com/cloudwego/netpoll-examples)