diff --git a/config/instance.go b/config/instance.go index 06a771d..cba8a03 100644 --- a/config/instance.go +++ b/config/instance.go @@ -28,6 +28,7 @@ type Instance struct { InterconnectSocketPath string `json:"interconnect_socket_path" toml:"interconnect_socket_path" yaml:"interconnect_socket_path"` DebugPort int `json:"debug_port" toml:"debug_port" yaml:"debug_port"` DebugMinutes int `json:"debug_minutes" toml:"debug_minutes" yaml:"debug_minutes"` + MetricsPort int `json:"metrics_port" toml:"metrics_port" yaml:"metrics_port"` YezzeyRestoreParanoid bool `json:"yezzey_restore_paranoid" toml:"yezzey_restore_paranoid" yaml:"yezzey_restore_paranoid"` @@ -71,6 +72,7 @@ const ( DefaultStorageConcurrency = 100 DefaultStatPort = 7432 DefaultPsqlPort = 8432 + DefaultMetricsPort = 2112 DefaultEndpointSourceScheme = "https" @@ -103,6 +105,9 @@ func EmbedDefaults(cfgInstance *Instance) { if cfgInstance.StorageCnf.StorageRateLimit == 0 { cfgInstance.StorageCnf.StorageRateLimit = DefaultStorageRateLimit } + if cfgInstance.MetricsPort == 0 { + cfgInstance.MetricsPort = DefaultMetricsPort + } cfgInstance.YezzeyRestoreParanoid = false } diff --git a/go.mod b/go.mod index 7318d2a..05427da 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,6 @@ module github.com/yezzey-gp/yproxy -go 1.24.0 - -toolchain go1.24.10 +go 1.25 require ( github.com/BurntSushi/toml v1.3.2 @@ -10,16 +8,19 @@ require ( github.com/jackc/pgx/v5 v5.6.0 github.com/jarcoal/httpmock v1.3.1 github.com/pkg/errors v0.9.1 + github.com/prometheus/client_golang v1.23.2 github.com/rs/zerolog v1.31.0 github.com/spf13/cobra v1.8.0 - github.com/stretchr/testify v1.8.4 + github.com/stretchr/testify v1.11.1 github.com/yezzey-gp/aws-sdk-go v0.1.0 go.uber.org/mock v0.4.0 - golang.org/x/sync v0.10.0 + golang.org/x/sync v0.16.0 + golang.org/x/sys v0.35.0 + golang.org/x/time v0.14.0 gopkg.in/yaml.v2 v2.4.0 ) -require golang.org/x/text v0.21.0 // indirect +require golang.org/x/text v0.28.0 // indirect require ( github.com/cockroachdb/apd v1.1.0 // indirect @@ -32,15 +33,17 @@ require ( ) require ( - github.com/golang/mock v1.6.0 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/leesper/go_rng v0.0.0-20190531154944-a612b043e353 // indirect - golang.org/x/crypto v0.30.0 // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.32.0 // indirect - golang.org/x/sys v0.28.0 // indirect - golang.org/x/time v0.14.0 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/prometheus/client_model v0.6.2 // indirect + github.com/prometheus/common v0.66.1 // indirect + github.com/prometheus/procfs v0.16.1 // indirect + go.yaml.in/yaml/v2 v2.4.2 // indirect + golang.org/x/crypto v0.41.0 // indirect gonum.org/v1/gonum v0.15.1 // indirect + google.golang.org/protobuf v1.36.8 // indirect ) require ( diff --git a/go.sum b/go.sum index c6f9622..2d1be32 100644 --- a/go.sum +++ b/go.sum @@ -2,9 +2,13 @@ github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8 github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c h1:kMFnB0vCcX7IL/m9Y5LO+KQYv+t1CQOiFe6+SV2J7bE= github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= +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/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/caio/go-tdigest v3.1.0+incompatible h1:uoVMJ3Q5lXmVLCCqaMGHLBWnbGoN6Lpu7OAUPR60cds= github.com/caio/go-tdigest v3.1.0+incompatible/go.mod h1:sHQM/ubZStBUmF1WbB8FAm8q9GjDajLC5T7ydxE3JHI= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= @@ -18,8 +22,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc= @@ -38,10 +42,14 @@ github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9Y github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/leesper/go_rng v0.0.0-20190531154944-a612b043e353 h1:X/79QL0b4YJVO5+OsPH9rF2u428CIrGL/jLmPsoOQQ4= github.com/leesper/go_rng v0.0.0-20190531154944-a612b043e353/go.mod h1:N0SVk0uhy+E1PZ3C9ctsPRlvOPAFPkCNlcPBDkt0N3U= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= @@ -53,10 +61,20 @@ github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APP github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/maxatome/go-testdeep v1.12.0 h1:Ql7Go8Tg0C1D/uMMX59LAoYK7LffeJQ6X2T04nTH68g= github.com/maxatome/go-testdeep v1.12.0/go.mod h1:lPZc/HAcJMP92l7yI6TRz1aZN5URwUBUAfUNvrclaNM= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= +github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= +github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs= +github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA= +github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= +github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= @@ -70,47 +88,40 @@ github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyh github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/yezzey-gp/aws-sdk-go v0.1.0 h1:as6ANEva14gKdhWPjZy6qaGR+/WhP0HN4UMzDHLDqmU= github.com/yezzey-gp/aws-sdk-go v0.1.0/go.mod h1:+gUq+WgyFOP6Eto+AcgJDDeM6tnXmOT4RJmfpuafV3Y= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= +go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= +go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY= -golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= +golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= -golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= +golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= +golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -120,8 +131,8 @@ golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= +golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= @@ -133,22 +144,19 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= +golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.15.1 h1:FNy7N6OUZVUaWG9pTiD+jlhdQ3lMP+/LcTpJ6+a8sQ0= gonum.org/v1/gonum v0.15.1/go.mod h1:eZTZuRFrzu5pcyjN5wJhcIhnUdNijYxX1T2IcrOGY0o= +google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc= +google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/pkg/clientpool/clientpool.go b/pkg/clientpool/clientpool.go index d0657a7..10a1c03 100644 --- a/pkg/clientpool/clientpool.go +++ b/pkg/clientpool/clientpool.go @@ -7,7 +7,11 @@ import ( "github.com/caio/go-tdigest" "github.com/yezzey-gp/yproxy/pkg/client" + "github.com/yezzey-gp/yproxy/pkg/metrics" "github.com/yezzey-gp/yproxy/pkg/ylogger" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" ) type Pool interface { @@ -89,6 +93,7 @@ func (c *PoolImpl) Pop(id uint) (bool, error) { } _ = c.opSpeed[ct][optyp].Add(float64(total) / float64(timeTotal)) + metrics.StoreLatencyAndSizeInfo(cl.OPType().String(), float64(total), float64(timeTotal)) } delete(c.pool, id) @@ -128,7 +133,7 @@ func (c *PoolImpl) ClientPoolForeach(cb func(client client.YproxyClient) error) } func NewClientPool() Pool { - return &PoolImpl{ + pool := &PoolImpl{ pool: map[uint]client.YproxyClient{}, mu: sync.Mutex{}, opSpeed: map[int]map[string]*tdigest.TDigest{ @@ -137,4 +142,14 @@ func NewClientPool() Pool { 2: {}, }, } + promauto.NewGaugeFunc(prometheus.GaugeOpts{ + Name: "client_connections", + Help: "The number of client connections to yproxy", + }, + func() float64 { + pool.mu.Lock() + defer pool.mu.Unlock() + return float64(len(pool.pool)) + }) + return pool } diff --git a/pkg/core/core.go b/pkg/core/core.go index ee6d578..a4a7a38 100644 --- a/pkg/core/core.go +++ b/pkg/core/core.go @@ -19,6 +19,7 @@ import ( "github.com/yezzey-gp/yproxy/pkg/core/pg" "github.com/yezzey-gp/yproxy/pkg/crypt" "github.com/yezzey-gp/yproxy/pkg/message" + "github.com/yezzey-gp/yproxy/pkg/metrics" "github.com/yezzey-gp/yproxy/pkg/proc" "github.com/yezzey-gp/yproxy/pkg/sdnotifier" "github.com/yezzey-gp/yproxy/pkg/storage" @@ -68,6 +69,7 @@ func (i *Instance) Run(instanceCnf *config.Instance) error { var listener net.Listener var iclistener net.Listener var dws *DebugWebServer + var mws *metrics.MetricsWebServer go func() { defer cancelCtx() @@ -137,14 +139,20 @@ func (i *Instance) Run(instanceCnf *config.Instance) error { dws = NewDebugWebServer(debugAddr) } - s, err := storage.NewStorage( - &instanceCnf.StorageCnf, - ) + if instanceCnf.MetricsPort != 0 { + metricsAddr := fmt.Sprintf("[::1]:%d", instanceCnf.MetricsPort) + mws = metrics.NewMetricsWebServer(metricsAddr) + if err := mws.Serve(); err != nil { + ylogger.Zero.Error().Err(err).Msg("failed to start metrics server") + } + } + + s, err := storage.NewStorage(&instanceCnf.StorageCnf, "yezzey") if err != nil { return err } - bs, err := storage.NewStorage(&instanceCnf.BackupStorageCnf) + bs, err := storage.NewStorage(&instanceCnf.BackupStorageCnf, "backup") if err != nil { return err } diff --git a/pkg/core/pg/pg.go b/pkg/core/pg/pg.go index 8aab9a6..b7615d0 100644 --- a/pkg/core/pg/pg.go +++ b/pkg/core/pg/pg.go @@ -376,7 +376,7 @@ func ProcessCopy(conn *pgproto3.Backend, prefix string, port uint64, oldCfgPath } config.EmbedDefaults(&instanceCnf) - oldStorage, err := storage.NewStorage(&instanceCnf.StorageCnf) + oldStorage, err := storage.NewStorage(&instanceCnf.StorageCnf, "") if err != nil { return err } diff --git a/pkg/metrics/metrics.go b/pkg/metrics/metrics.go new file mode 100644 index 0000000..23d97af --- /dev/null +++ b/pkg/metrics/metrics.go @@ -0,0 +1,127 @@ +package metrics + +import ( + "net/http" + + "sync" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/prometheus/client_golang/prometheus/promhttp" +) + +var ( + latencyBuckets = []float64{0.001, 0.01, 0.05, 0.1, 0.5, 1, 5, 10, 50, 100, 500, 1000} + sizeBuckets = []float64{1, 128, 1024, 128 * 1024, 1024 * 1024, 2 * 1024 * 1024, 8 * 1024 * 1024, 16 * 1024 * 1024, 128 * 1024 * 1024, 1024 * 1024 * 1024} + + HandlerNames = map[string]bool{ + "READ": true, + "WRITE": true, + "LIMIT_READ": true, + "LIMIT_WRITE": true, + "S3_PUT": true, + "S3_GET": true, + "CAT": true, + "CATV2": true, + "PUT": true, + "PUTV2": true, + "PUTV3": true, + "DELETE": true, + "LIST": true, + "LISTV2": true, + "OBJECT META": true, + "COPY": true, + "COPYV2": true, + "GOOL": true, + "ERROR": true, + "UNTRASHIFY": true, + "COLLECT OBSOLETE": true, + "DELETE OBSOLETE": true, + } +) + +func StoreLatencyAndSizeInfo(opType string, size float64, latency float64) { + if _, ok := HandlerNames[opType]; !ok { + return + } + HistogramSizeVec.With(map[string]string{ + "source": opType, + }).Observe(size) + if size != 0 { + HistogramLatencyVec.With(map[string]string{ + "source": opType, + }).Observe(latency / size) + } +} + +var ( + ReadReqProcessed = promauto.NewCounter(prometheus.CounterOpts{ + Name: "read_req_processed_total", + Help: "The total number of processed reads", + }) + ReadReqErrors = promauto.NewCounter(prometheus.CounterOpts{ + Name: "read_req_errors_total", + Help: "The total number of errors during reads", + }) + WiteReqProcessed = promauto.NewCounter(prometheus.CounterOpts{ + Name: "write_req_processed_total", + Help: "The total number of processed writes", + }) + WriteReqErrors = promauto.NewCounter(prometheus.CounterOpts{ + Name: "write_req_errors_total", + Help: "The total number of errors during reads", + }) + HistogramLatencyVec = promauto.NewHistogramVec(prometheus.HistogramOpts{ + Name: "request_latency", + Help: "Request latency in seconds", + Buckets: latencyBuckets, + }, []string{"source"}) + + HistogramSizeVec = promauto.NewHistogramVec(prometheus.HistogramOpts{ + Name: "request_size", + Help: "Request latency in seconds", + Buckets: sizeBuckets, + }, []string{"source"}) +) + +func NewMetricsWebServer(httpAddr string) *MetricsWebServer { + return &MetricsWebServer{ + httpAddr: httpAddr, + } +} + +type MetricsWebServer struct { + *http.Server + *http.ServeMux + mu sync.Mutex + httpAddr string +} + +func (mws *MetricsWebServer) Serve() error { + mws.mu.Lock() + defer mws.mu.Unlock() + + mws.configureDebugWebServer() + + go func() { + _ = mws.ListenAndServe() + }() + + return nil +} + +func (mws *MetricsWebServer) configureDebugWebServer() { + mux := http.NewServeMux() + mws.Server = &http.Server{ + Addr: mws.httpAddr, + Handler: mux, + } + mws.ServeMux = mux + + mws.enablePrometheusEndpoints() +} + +// enablePrometheusEndpoints exposes prometheus http endpoints. +func (dws *MetricsWebServer) enablePrometheusEndpoints() { + dws.HandleFunc("/metrics", promhttp.Handler().ServeHTTP) +} diff --git a/pkg/proc/interaction.go b/pkg/proc/interaction.go index 4aa3c4c..d39ba6f 100644 --- a/pkg/proc/interaction.go +++ b/pkg/proc/interaction.go @@ -254,7 +254,7 @@ func ProcessCopyExtended( return nil } config.EmbedDefaults(&sourceInstanceCnf) - oldStorage, err := storage.NewStorage(&sourceInstanceCnf.StorageCnf) + oldStorage, err := storage.NewStorage(&sourceInstanceCnf.StorageCnf, "") if err != nil { return err } diff --git a/pkg/proc/yio/limiter/limiter.go b/pkg/proc/yio/limiter/limiter.go index 8f40d0d..b50f0b5 100644 --- a/pkg/proc/yio/limiter/limiter.go +++ b/pkg/proc/yio/limiter/limiter.go @@ -5,8 +5,10 @@ import ( "fmt" "io" "sync" + "time" "github.com/yezzey-gp/yproxy/config" + "github.com/yezzey-gp/yproxy/pkg/metrics" "github.com/yezzey-gp/yproxy/pkg/ylogger" "golang.org/x/time/rate" ) @@ -30,24 +32,44 @@ func NewReader(reader io.ReadCloser, limiter *rate.Limiter) *Reader { } } +func (r *Reader) Wait(n int) error { + if r.limiter == nil { + return nil + } + start := time.Now() + err := r.limiter.WaitN(r.ctx, n) + waitTime := time.Since(start).Nanoseconds() + metrics.StoreLatencyAndSizeInfo("LIMIT_READ", float64(n), float64(waitTime)) + return err +} + +func (r *Reader) getBurstableLimit(n int) int { + if r.limiter == nil { + return n + } + return min(r.limiter.Burst(), n) +} + func (r *Reader) Read(buf []byte) (int, error) { if len(buf) == 0 { return 0, fmt.Errorf("empty buffer passed") } - end := min(r.limiter.Burst(), len(buf)) + end := r.getBurstableLimit(len(buf)) + // we do not know how many bytes we could read, so first - read data n, err := r.reader.Read(buf[:end]) + // and then wait in a limiter to correct measure processed data if err != nil { N := max(n, 0) - limiterErr := r.limiter.WaitN(r.ctx, N) + limiterErr := r.Wait(N) if limiterErr != nil { ylogger.Zero.Error().Err(limiterErr).Msg("Error happened while limiting") } return n, err } - err = r.limiter.WaitN(r.ctx, n) + err = r.Wait(n) return n, err } @@ -70,24 +92,31 @@ func NewWriter(writer io.WriteCloser, limiter *rate.Limiter) *Writer { } } +func (w *Writer) Wait(n int) error { + start := time.Now() + err := w.limiter.WaitN(w.ctx, n) + waitTime := time.Since(start).Nanoseconds() + metrics.StoreLatencyAndSizeInfo("LIMIT_WRITE", float64(n), float64(waitTime)) + return err +} + +func (w *Writer) getBurstableLimit(n int) int { + return min(w.limiter.Burst(), n) +} + func (r *Writer) Write(buf []byte) (int, error) { if len(buf) == 0 { return 0, fmt.Errorf("empty buffer passed") } - end := min(r.limiter.Burst(), len(buf)) - n, err := r.writer.Write(buf[:end]) - - if err != nil { - N := max(n, 0) - limiterErr := r.limiter.WaitN(r.ctx, N) - if limiterErr != nil { - ylogger.Zero.Error().Err(limiterErr).Msg("Error happened while limiting") - } - return n, err + end := r.getBurstableLimit(len(buf)) + // in a case of write we should wait before handling query + limiterErr := r.Wait(end) + if limiterErr != nil { + ylogger.Zero.Error().Err(limiterErr).Msg("Error happened while limiting") } + n, err := r.writer.Write(buf[:end]) - err = r.limiter.WaitN(r.ctx, n) return n, err } diff --git a/pkg/proc/yio/yrreader.go b/pkg/proc/yio/yrreader.go index 0f91f85..8e44094 100644 --- a/pkg/proc/yio/yrreader.go +++ b/pkg/proc/yio/yrreader.go @@ -7,6 +7,7 @@ import ( "github.com/yezzey-gp/yproxy/config" "github.com/yezzey-gp/yproxy/pkg/client" + "github.com/yezzey-gp/yproxy/pkg/metrics" "github.com/yezzey-gp/yproxy/pkg/proc/yio/limiter" "github.com/yezzey-gp/yproxy/pkg/settings" "github.com/yezzey-gp/yproxy/pkg/storage" @@ -122,12 +123,16 @@ func (y *YproxyRetryReader) Read(p []byte) (int, error) { y.needReacquire = false } - + start := time.Now() n, err := y.underlying.Read(p) + readTime := time.Since(start).Nanoseconds() + metrics.ReadReqProcessed.Inc() + metrics.StoreLatencyAndSizeInfo("READ", float64(n), float64(readTime)) if err == io.EOF { return n, err } if err != nil || n < 0 { + metrics.ReadReqErrors.Inc() ylogger.Zero.Error().Err(err).Int64("offset reached", y.offsetReached).Int("bytes half-read", n).Int("retry count", int(retry)).Msg("encounter read error") if n > 0 { diff --git a/pkg/proc/yio/ywriter.go b/pkg/proc/yio/ywriter.go index 3a3130d..b621ad2 100644 --- a/pkg/proc/yio/ywriter.go +++ b/pkg/proc/yio/ywriter.go @@ -2,9 +2,11 @@ package yio import ( "io" + "time" "github.com/yezzey-gp/yproxy/config" "github.com/yezzey-gp/yproxy/pkg/client" + "github.com/yezzey-gp/yproxy/pkg/metrics" "github.com/yezzey-gp/yproxy/pkg/proc/yio/limiter" "github.com/yezzey-gp/yproxy/pkg/ylogger" "golang.org/x/time/rate" @@ -27,11 +29,17 @@ func (y *YproxyWriter) Close() error { } func (y *YproxyWriter) Write(p []byte) (n int, err error) { + + start := time.Now() n, err = y.underlying.Write(p) + writeTime := time.Since(start).Nanoseconds() + metrics.WiteReqProcessed.Inc() + metrics.StoreLatencyAndSizeInfo("WRITE", float64(n), float64(writeTime)) y.offsetReached += int64(n) y.selfCl.SetByteOffset(y.offsetReached) if err != nil { + metrics.WriteReqErrors.Inc() ylogger.Zero.Error().Uint("client id", y.selfCl.ID()).Int("bytes write", n).Err(err).Msg("failed to write into underlying connection") } diff --git a/pkg/storage/s3storage.go b/pkg/storage/s3storage.go index 4c8edd1..eaa01b7 100644 --- a/pkg/storage/s3storage.go +++ b/pkg/storage/s3storage.go @@ -18,6 +18,7 @@ import ( "github.com/yezzey-gp/aws-sdk-go/service/s3/s3manager" "github.com/yezzey-gp/yproxy/config" "github.com/yezzey-gp/yproxy/pkg/message" + "github.com/yezzey-gp/yproxy/pkg/metrics" "github.com/yezzey-gp/yproxy/pkg/object" "github.com/yezzey-gp/yproxy/pkg/settings" "github.com/yezzey-gp/yproxy/pkg/tablespace" @@ -53,6 +54,7 @@ var _ StorageInteractor = &S3StorageInteractor{} func (s *S3StorageInteractor) CatFileFromStorage(name string, offset int64, setts []settings.StorageSettings) (io.ReadCloser, error) { + timeStart := time.Now() objectPath := strings.TrimLeft(path.Join(s.cnf.StoragePrefix, name), "/") tableSpace := ResolveStorageSetting(setts, message.TableSpaceSetting, tablespace.DefaultTableSpace) @@ -79,11 +81,18 @@ func (s *S3StorageInteractor) CatFileFromStorage(name string, offset int64, sett ylogger.Zero.Debug().Str("key", objectPath).Int64("offset", offset).Str("bucket", bucket).Msg("requesting external storage") object, err := sess.GetObject(input) + getTime := time.Since(timeStart).Nanoseconds() + objLen := 1.0 + if object.ContentLength != nil { + objLen = float64(*object.ContentLength) + } + metrics.StoreLatencyAndSizeInfo("S3_GET", objLen, float64(getTime)) return object.Body, err } func (s *S3StorageInteractor) PutFileToDest(name string, r io.Reader, settings []settings.StorageSettings) error { + timeStart := time.Now() objectPath := strings.TrimLeft(path.Join(s.cnf.StoragePrefix, name), "/") storageClass := ResolveStorageSetting(settings, message.StorageClassSetting, "STANDARD") @@ -116,7 +125,7 @@ func (s *S3StorageInteractor) PutFileToDest(name string, r io.Reader, settings [ uploader.PartSize = int64(multipartChunkSize) uploader.Concurrency = 1 }) - + putLen := int(multipartChunkSize) if multipartUpload { s.multipartUploads.Store(objectPath, true) _, err = up.Upload( @@ -134,6 +143,7 @@ func (s *S3StorageInteractor) PutFileToDest(name string, r io.Reader, settings [ if err != nil { return err } + putLen = len(body) _, err = sess.PutObject(&s3.PutObjectInput{ Bucket: aws.String(bucket), Key: aws.String(objectPath), @@ -142,6 +152,8 @@ func (s *S3StorageInteractor) PutFileToDest(name string, r io.Reader, settings [ }) } + putTime := time.Since(timeStart).Nanoseconds() + metrics.StoreLatencyAndSizeInfo("S3_PUT", float64(putLen), float64(putTime)) return err } diff --git a/pkg/storage/sessionpool.go b/pkg/storage/sessionpool.go index a56084d..ff8efca 100644 --- a/pkg/storage/sessionpool.go +++ b/pkg/storage/sessionpool.go @@ -22,6 +22,9 @@ import ( "github.com/yezzey-gp/yproxy/pkg/ylogger" "golang.org/x/sync/semaphore" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" ) type SessionPool interface { @@ -41,11 +44,19 @@ func (sp *S3SessionPool) StorageUsedConcurrency() int { return int(sp.usedConnections.Load()) } -func NewSessionPool(cnf *config.Storage) SessionPool { - return &S3SessionPool{ +func NewSessionPool(cnf *config.Storage, poolName string) SessionPool { + pool := &S3SessionPool{ cnf: cnf, sem: semaphore.NewWeighted(cnf.StorageConcurrency), } + if poolName != "" { + promauto.NewGaugeFunc(prometheus.GaugeOpts{ + Name: "external_connections_" + poolName, + Help: "The number of external connections to S3 storage", + }, + func() float64 { return float64(pool.StorageUsedConcurrency()) }) + } + return pool } // TODO : unit tests diff --git a/pkg/storage/sessionpool_test.go b/pkg/storage/sessionpool_test.go index d3ea1ff..08f81a6 100644 --- a/pkg/storage/sessionpool_test.go +++ b/pkg/storage/sessionpool_test.go @@ -33,7 +33,7 @@ func TestEndpointSourceHTTP(t *testing.T) { StorageRegion: "us-east-1", StorageConcurrency: 1, - }) + }, "s3") sess, err := pool.GetSession(context.TODO(), &config.StorageCredentials{ AccessKeyId: "mock_access_key", @@ -72,7 +72,7 @@ func TestEndpointSourceHTTPS(t *testing.T) { StorageRegion: "us-east-1", StorageConcurrency: 1, - }) + }, "https") sess, err := pool.GetSession(context.TODO(), &config.StorageCredentials{ AccessKeyId: "mock_access_key", @@ -112,7 +112,7 @@ func TestEndpointSourceSetPort(t *testing.T) { StorageRegion: "us-east-1", StorageConcurrency: 1, - }) + }, "setport") sess, err := pool.GetSession(context.TODO(), &config.StorageCredentials{ AccessKeyId: "mock_access_key", diff --git a/pkg/storage/storage.go b/pkg/storage/storage.go index 417b68d..b7fb26f 100644 --- a/pkg/storage/storage.go +++ b/pkg/storage/storage.go @@ -47,7 +47,7 @@ type StorageInteractor interface { DefaultBucket() string } -func NewStorage(cnf *config.Storage) (StorageInteractor, error) { +func NewStorage(cnf *config.Storage, storageName string) (StorageInteractor, error) { switch cnf.StorageType { case "fs": return &FileStorageInteractor{ @@ -55,7 +55,7 @@ func NewStorage(cnf *config.Storage) (StorageInteractor, error) { }, nil case "s3": return &S3StorageInteractor{ - pool: NewSessionPool(cnf), + pool: NewSessionPool(cnf, storageName), cnf: cnf, TSToBucketMap: buildBucketMapFromCnf(cnf), credentialMap: buildCredMapFromCnf(cnf),