Skip to content

Commit

Permalink
Merge pull request #196 from ipfs-force-community/feat/add-metrics
Browse files Browse the repository at this point in the history
feat: add more metrics
  • Loading branch information
simlecode authored Dec 7, 2023
2 parents d00c2e1 + f8d0d45 commit 8ea5a7a
Show file tree
Hide file tree
Showing 7 changed files with 170 additions and 23 deletions.
11 changes: 11 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,17 @@ issues:
linters-settings:
goconst:
min-occurrences: 6


revive:
rules:
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unused-parameter
- name: unused-parameter
severity: warning
disabled: true
arguments:
- allowRegex: "^_"


run:
skip-dirs-use-default: false
Expand Down
116 changes: 103 additions & 13 deletions auth/jwt.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (

"github.com/gbrlsnchs/jwt/v3"
"github.com/google/uuid"
"go.opencensus.io/tag"
"golang.org/x/xerrors"

"github.com/filecoin-project/go-address"
Expand Down Expand Up @@ -86,11 +87,47 @@ type JWTPayload struct {
}

func NewOAuthService(dbPath string, cnf *config.DBConfig) (OAuthService, error) {
ctx := context.Background()
store, err := storage.NewStore(cnf, dbPath)
if err != nil {
return nil, err
}

// check amount of token and user
tokens, err := store.List(0, 0)
if err != nil {
return nil, fmt.Errorf("check token: %w", err)
}
tokenCount := map[core.Permission]int64{
core.PermRead: 0,
core.PermWrite: 0,
core.PermSign: 0,
core.PermAdmin: 0,
}
for _, token := range tokens {
tokenCount[token.Perm]++
}
for perm, count := range tokenCount {
core.TokenGauge.Set(ctx, perm, count)
}

// check user
users, err := store.ListUsers(0, 1, core.UserStateUndefined)
if err != nil {
return nil, fmt.Errorf("check user: %w", err)
}
userCount := map[core.UserState]int64{
core.UserStateUndefined: 0,
core.UserStateEnabled: 0,
core.UserStateDisabled: 0,
}
for _, user := range users {
userCount[user.State] += 1
}
for state, count := range userCount {
core.UserGauge.Set(ctx, state.String(), count)
}

jwtOAuthInstance = &jwtOAuth{
store: store,
mp: newMapper(),
Expand Down Expand Up @@ -137,30 +174,52 @@ func (o *jwtOAuth) GenerateToken(ctx context.Context, pl *JWTPayload) (string, e
if err != nil {
return core.EmptyString, xerrors.Errorf("store token failed :%s", err)
}

core.TokenGauge.Inc(ctx, pl.Perm, 1)
return token.String(), nil
}

func (o *jwtOAuth) Verify(ctx context.Context, token string) (*JWTPayload, error) {
err := permCheck(ctx, core.PermRead)
func (o *jwtOAuth) Verify(ctx context.Context, token string) (payload *JWTPayload, err error) {
defer func() {
if payload != nil {
ctx, _ = tag.New(ctx, tag.Upsert(core.TagPerm, payload.Perm), tag.Upsert(core.TagTokenName, payload.Name))
}
if err != nil {
ctx, _ = tag.New(ctx, tag.Upsert(core.TagVerifyState, core.VerifyStateFailed))
} else {
ctx, _ = tag.New(ctx, tag.Upsert(core.TagVerifyState, core.VerifyStateSuccess))
}
core.TokenVerifyCounter.Tick(ctx)
}()

payload, err = DecodeToken(token)
if err != nil {
return nil, fmt.Errorf("need read prem: %w", err)
return
}

err = permCheck(ctx, core.PermRead)
if err != nil {
err = fmt.Errorf("need read prem: %w", err)
return
}

p := new(JWTPayload)
tk := []byte(token)

kp, err := o.store.Get(storage.Token(token))
if err != nil {
return nil, xerrors.Errorf("get token: %v", err)
err = xerrors.Errorf("get token: %v", err)
return
}
secret, err := hex.DecodeString(kp.Secret)
if err != nil {
return nil, xerrors.Errorf("decode secret %v", err)
err = xerrors.Errorf("decode secret %v", err)
return
}
if _, err := jwt.Verify(tk, jwt.NewHS256(secret), p); err != nil {
return nil, ErrorVerificationFailed
if _, err = jwt.Verify(tk, jwt.NewHS256(secret), payload); err != nil {
err = ErrorVerificationFailed
return
}
return p, nil
return
}

type TokenInfo struct {
Expand Down Expand Up @@ -249,6 +308,9 @@ func (o *jwtOAuth) RemoveToken(ctx context.Context, token string) error {
if err != nil {
return fmt.Errorf("remove token %s: %w", token, err)
}

payload, _ := DecodeToken(token)
core.TokenGauge.Inc(ctx, payload.Perm, -1)
return nil
}

Expand All @@ -262,6 +324,9 @@ func (o *jwtOAuth) RecoverToken(ctx context.Context, token string) error {
if err != nil {
return fmt.Errorf("recover token %s: %w", token, err)
}

payload, _ := DecodeToken(token)
core.TokenGauge.Inc(ctx, payload.Perm, 1)
return nil
}

Expand Down Expand Up @@ -297,6 +362,7 @@ func (o *jwtOAuth) CreateUser(ctx context.Context, req *CreateUserRequest) (*Cre
if err != nil {
return nil, err
}
core.UserGauge.Inc(ctx, userNew.State.String(), 1)
return o.mp.ToOutPutUser(userNew), nil
}

Expand Down Expand Up @@ -356,16 +422,25 @@ func (o *jwtOAuth) DeleteUser(ctx context.Context, req *DeleteUserRequest) error
if err != nil {
return fmt.Errorf("need admin prem: %w", err)
}

return o.store.DeleteUser(req.Name)
err = o.store.DeleteUser(req.Name)
if err != nil {
return err
}
core.UserGauge.Inc(ctx, core.UserStateDisabled.String(), -1)
return nil
}

func (o *jwtOAuth) RecoverUser(ctx context.Context, req *RecoverUserRequest) error {
err := permCheck(ctx, core.PermAdmin)
if err != nil {
return fmt.Errorf("need admin prem: %w", err)
}
return o.store.RecoverUser(req.Name)
err = o.store.RecoverUser(req.Name)
if err != nil {
return err
}
core.UserGauge.Inc(ctx, core.UserStateDisabled.String(), 1)
return nil
}

func (o *jwtOAuth) GetUserByMiner(ctx context.Context, req *GetUserByMinerRequest) (*OutputUser, error) {
Expand Down Expand Up @@ -630,7 +705,7 @@ func DecodeToBytes(enc []byte) ([]byte, error) {

func JwtUserFromToken(token string) (string, error) {
sks := strings.Split(token, ".")
if len(sks) < 1 {
if len(sks) < 2 {
return "", fmt.Errorf("can't parse user from input token")
}
dec, err := DecodeToBytes([]byte(sks[1]))
Expand All @@ -643,6 +718,21 @@ func JwtUserFromToken(token string) (string, error) {
return payload.Name, err
}

func DecodeToken(token string) (*JWTPayload, error) {
sks := strings.Split(token, ".")
if len(sks) < 2 {
return nil, fmt.Errorf("can't parse user from input token")
}
dec, err := DecodeToBytes([]byte(sks[1]))
if err != nil {
return nil, err
}
payload := &JWTPayload{}
err = json.Unmarshal(dec, payload)

return payload, err
}

func IsSignerAddress(addr address.Address) bool {
protocol := addr.Protocol()
return protocol == address.SECP256K1 || protocol == address.BLS || protocol == address.Delegated
Expand Down
13 changes: 13 additions & 0 deletions cli/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/ipfs-force-community/metrics"
"github.com/ipfs-force-community/sophon-auth/auth"
"github.com/ipfs-force-community/sophon-auth/config"
"github.com/ipfs-force-community/sophon-auth/core"
"github.com/ipfs-force-community/sophon-auth/log"
"github.com/ipfs-force-community/sophon-auth/util"
"github.com/urfave/cli/v2"
Expand Down Expand Up @@ -78,6 +79,7 @@ func fillConfigByFlag(cnf *config.Config, cliCtx *cli.Context) *config.Config {
}

func run(cliCtx *cli.Context) error {
ctx := cliCtx.Context
repoPath, err := GetRepoPath(cliCtx)
if err != nil {
return err
Expand Down Expand Up @@ -136,6 +138,14 @@ func run(cliCtx *cli.Context) error {
}
}

// set up metrics
if cnf.Metrics != nil {
err := metrics.SetupMetrics(ctx, cnf.Metrics)
if err != nil {
log.Warnf("setup metrics: %s", err)
}
}

server := &http.Server{
Addr: cnf.Listen,
Handler: router,
Expand All @@ -144,5 +154,8 @@ func run(cliCtx *cli.Context) error {
IdleTimeout: cnf.IdleTimeout,
}
log.Infof("server start and listen on %s", cnf.Listen)

core.ApiState.Set(ctx, 1)
defer core.ApiState.Set(ctx, 0)
return server.ListenAndServe()
}
21 changes: 14 additions & 7 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ import (
)

type Config struct {
Listen string `json:"listen"`
ReadTimeout time.Duration `json:"readTimeout"`
WriteTimeout time.Duration `json:"writeTimeout"`
IdleTimeout time.Duration `json:"idleTimeout"`
Log *LogConfig `json:"log"`
DB *DBConfig `json:"db"`
Trace *metrics.TraceConfig `json:"traceConfig"`
Listen string `json:"listen"`
ReadTimeout time.Duration `json:"readTimeout"`
WriteTimeout time.Duration `json:"writeTimeout"`
IdleTimeout time.Duration `json:"idleTimeout"`
Log *LogConfig `json:"log"`
DB *DBConfig `json:"db"`

Trace *metrics.TraceConfig `json:"traceConfig"`
Metrics *metrics.MetricsConfig `json:"metricsExporter"`
}

type DBType = string
Expand Down Expand Up @@ -49,6 +51,10 @@ func RandSecret() ([]byte, error) {
}

func DefaultConfig() *Config {
defMetricsCfg := metrics.DefaultMetricsConfig()
defMetricsCfg.Exporter.Graphite.Namespace = "sophon_auth"
defMetricsCfg.Exporter.Prometheus.Namespace = "sophon_auth"

return &Config{
Listen: "127.0.0.1:8989",
ReadTimeout: time.Minute,
Expand All @@ -60,6 +66,7 @@ func DefaultConfig() *Config {
JaegerEndpoint: "localhost:6831",
ServerName: "sophon-auth",
},
Metrics: defMetricsCfg,
Log: &LogConfig{
LogLevel: "trace",
HookSwitch: false,
Expand Down
26 changes: 26 additions & 0 deletions core/metrics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package core

import (
"github.com/ipfs-force-community/metrics"
"go.opencensus.io/tag"
)

var (
emptyUnit = ""

VerifyStateFailed = "failed"
VerifyStateSuccess = "success"

TagPerm = tag.MustNewKey("perm")
TagUserState = tag.MustNewKey("user_state")
TagTokenName = tag.MustNewKey("token_name")
TagUserName = tag.MustNewKey("user_name")
TagVerifyState = tag.MustNewKey("verify_state")
)

var (
TokenGauge = metrics.NewInt64WithCategory("token/amount", "amount of token", emptyUnit)
UserGauge = metrics.NewInt64WithCategory("user/amount", "amount of user", emptyUnit)
TokenVerifyCounter = metrics.NewCounter("token/verify", "amount of token verify", TagPerm, TagVerifyState)
ApiState = metrics.NewInt64("api/state", "api service state. 0: down, 1: up", emptyUnit)
)
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ require (
github.com/golang/mock v1.6.0
github.com/google/uuid v1.3.0
github.com/influxdata/influxdb-client-go/v2 v2.2.2
github.com/ipfs-force-community/metrics v1.0.1-0.20231011024528-8c881d456601
github.com/ipfs-force-community/metrics v1.0.1-0.20231205060849-0b0d16ed0e8d
github.com/ipfs/go-log/v2 v2.5.1
github.com/mitchellh/go-homedir v1.1.0
github.com/multiformats/go-multiaddr v0.8.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -319,8 +319,8 @@ github.com/influxdata/influxdb-client-go/v2 v2.2.2 h1:O0CGIuIwQafvAxttAJ/VqMKfbW
github.com/influxdata/influxdb-client-go/v2 v2.2.2/go.mod h1:fa/d1lAdUHxuc1jedx30ZfNG573oQTQmUni3N6pcW+0=
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 h1:W9WBk7wlPfJLvMCdtV4zPulc4uCPrlywQOmbFOhgQNU=
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo=
github.com/ipfs-force-community/metrics v1.0.1-0.20231011024528-8c881d456601 h1:zxKQ30KAD6KfvSFAx9tuqQXLDsEHyF+eVaUBXXYC2bU=
github.com/ipfs-force-community/metrics v1.0.1-0.20231011024528-8c881d456601/go.mod h1:wM6EmkEcnJgWOFcVytgvK0u15awEmt8He0f2kAdsFDA=
github.com/ipfs-force-community/metrics v1.0.1-0.20231205060849-0b0d16ed0e8d h1:U7aqH9MnV+HNErbZ4VNhr0tKk158GjTXvNfsj8UDZjI=
github.com/ipfs-force-community/metrics v1.0.1-0.20231205060849-0b0d16ed0e8d/go.mod h1:wM6EmkEcnJgWOFcVytgvK0u15awEmt8He0f2kAdsFDA=
github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY=
github.com/ipfs/go-block-format v0.1.1 h1:129vSO3zwbsYADcyQWcOYiuCpAqt462SFfqFHdFJhhI=
github.com/ipfs/go-block-format v0.1.1/go.mod h1:+McEIT+g52p+zz5xGAABGSOKrzmrdX97bc0USBdWPUs=
Expand Down

0 comments on commit 8ea5a7a

Please sign in to comment.