hippo

package module
v1.5.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 7, 2020 License: MIT Imports: 18 Imported by: 2

README

Hippo Logo

Hippo

A Microservices Toolkit.

Hippo is a collection of well crafted go packages that help you build robust, reliable, maintainable microservices. It is not a full-fledged framework with lot of magic, predefined architecture, specific patterns and bullshit opinions so you will be the one behind the wheel.

It provides libraries to implement components for service discovery, async jobs, authentication, authorization, logging, caching, metrics, tracing, rate-limiting...etc which are essential requirements for running microservices in production.

Documentation

Installation:

go get -u github.com/clivern/hippo
import (
    "github.com/clivern/hippo"
)

Components:

HTTP Requests Component


httpClient := hippo.NewHTTPClient()

// Get Request
response, err := httpClient.Get(
    "https://httpbin.org/get",
    map[string]string{"url_arg_key": "url_arg_value"},
    map[string]string{"header_key": "header_value"},
)

// Delete Request
response, err := httpClient.Delete(
    "https://httpbin.org/delete",
    map[string]string{"url_arg_key": "url_arg_value"},
    map[string]string{"header_key": "header_value"},
)

// Post Request
response, err := httpClient.Post(
    "https://httpbin.org/post",
    `{"RequestBodyKey":"RequestBodyValue"}`,
    map[string]string{"url_arg_key": "url_arg_value"},
    map[string]string{"header_key": "header_value"},
)

// Put Request
response, err := httpClient.Put(
    "https://httpbin.org/put",
    `{"RequestBodyKey":"RequestBodyValue"}`,
    map[string]string{"url_arg_key": "url_arg_value"},
    map[string]string{"header_key": "header_value"},
)

// ....

statusCode := httpClient.GetStatusCode(response)
responseBody, err := httpClient.ToString(response)

Cache/Redis Component

driver := hippo.NewRedisDriver("localhost:6379", "password", 0)

// connect to redis server
ok, err := driver.Connect()
// ping check
ok, err = driver.Ping()

// set an item
ok, err = driver.Set("app_name", "Hippo", 0)
// check if exists
ok, err = driver.Exists("app_name")
// get value
value, err := driver.Get("app_name")
// delete an item
count, err := driver.Del("app_name")

// hash set
ok, err = driver.HSet("configs", "app_name", "Hippo")
// check if item on a hash
ok, err = driver.HExists("configs", "app_name")
// get item from a hash
value, err = driver.HGet("configs", "app_name")
// hash length
count, err = driver.HLen("configs")
// delete item from a hash
count, err = driver.HDel("configs", "app_name")
// clear the hash
count, err = driver.HTruncate("configs")

// Pub/Sub
driver.Publish("hippo", "Hello")
driver.Subscribe("hippo", func(message hippo.Message) error {
    // message.Channel
    // message.Payload
    return nil
})

Time Series/Graphite Component

import "time"


metric := hippo.NewMetric("hippo1.up", "23", time.Now().Unix()) // Type is hippo.Metric

metrics := hippo.NewMetrics("hippo2.up", "35", time.Now().Unix()) // type is []hippo.Metric
metrics = append(metrics, hippo.NewMetric("hippo2.down", "40", time.Now().Unix()))
metrics = append(metrics, hippo.NewMetric("hippo2.error", "70", time.Now().Unix()))

// NewGraphite(protocol string, host string, port int, prefix string)
// protocol can be tcp, udp or nop
// prefix is a metric prefix
graphite := hippo.NewGraphite("tcp", "127.0.0.1", 2003, "")
error := graphite.Connect()

if error == nil{
    // send one by one
    graphite.SendMetric(metric)

    // bulk send
    graphite.SendMetrics(metrics)
}

System Stats Component

// func NewSystemStats(enableCPU, enableMem, enableGC bool) *SystemStats {
stats := hippo.NewSystemStats(true, true, true)
stats.GetStats() // type map[string]uint64
// map[cpu.cgo_calls:0 cpu.goroutines:1 mem.alloc:0....]

Correlation ID Component

correlation := hippo.NewCorrelation()
correlation.UUIDv4()

Workers Pool Component

import "fmt"

tasks := []*hippo.Task{
    hippo.NewTask(func() (string, error) {
        fmt.Println("Task #1")
        return "Result 1", nil
    }),
    hippo.NewTask(func() (string, error) {
        fmt.Println("Task #2")
        return "Result 2", nil
    }),
    hippo.NewTask(func() (string, error) {
        fmt.Println("Task #3")
        return "Result 3", nil
    }),
}

// hippo.NewWorkersPool(tasks []*Task, concurrency int) *WorkersPool
p := hippo.NewWorkersPool(tasks, 2)
p.Run()

var numErrors int
for _, task := range p.Tasks {
    if task.Err != nil {
        fmt.Println(task.Err)
        numErrors++
    } else {
        fmt.Println(task.Result)
    }
    if numErrors >= 10 {
        fmt.Println("Too many errors.")
        break
    }
}

Health Checker Component

import "fmt"

healthChecker := hippo.NewHealthChecker()
healthChecker.AddCheck("ping_check", func() (bool, error){
    return true, nil
})
healthChecker.AddCheck("db_check", func() (bool, error){
    return false, fmt.Errorf("Database Down")
})
healthChecker.RunChecks()

fmt.Println(healthChecker.ChecksStatus())
// Output -> DOWN
fmt.Println(healthChecker.ChecksReport())
// Output -> [{"id":"ping_check","status":"UP","error":"","result":true},{"id":"db_check","status":"DOWN","error":"Database Down","result":false}] <nil>
import "fmt"

healthChecker := hippo.NewHealthChecker()

healthChecker.AddCheck("url_check", func() (bool, error){
    return hippo.HTTPCheck("httpbin_service", "https://httpbin.org/status/503", map[string]string{}, map[string]string{})
})
healthChecker.AddCheck("redis_check", func() (bool, error){
    return hippo.RedisCheck("redis_service", "localhost:6379", "", 0)
})
healthChecker.RunChecks()

fmt.Println(healthChecker.ChecksStatus())
// Outputs -> DOWN
fmt.Println(healthChecker.ChecksReport())
// Outputs -> [{"id":"url_check","status":"DOWN","error":"Service httpbin_service is unavailable","result":false},{"id":"redis_check","status":"DOWN","error":"Error while connecting redis_service: dial tcp [::1]:6379: connect: connection refused","result":false}] <nil>

API Rate Limiting


import "time"

// Create a limiter with a specific identifier(IP address or access token or username....etc)
// NewCallerLimiter(identifier string, eventsRate rate.Limit, tokenBurst int) *rate.Limiter
limiter := hippo.NewCallerLimiter("10.10.10.10", 100, 1)
if limiter.Allow() == false {
    // Don't allow access
} else {
    // Allow Access
}


// auto clean old clients (should run as background process)
// CleanupCallers(cleanAfter time.Duration)
go func(){
    for {
        time.Sleep(60 * time.Second)
        hippo.CleanupCallers(60)
    }
}()

Logger Component

logger, _ := hippo.NewLogger("debug", "json", []string{"stdout", "/var/log/error.log"})

logger.Info("Hello World!")
logger.Debug("Hello World!")
logger.Warn("Hello World!")
logger.Error("Hello World!")

defer logger.Sync()

// check if path exists
exists := hippo.PathExists("/var/log")

// check if file exists
exists := hippo.FileExists("/var/log/error.log")

// check if dir exists
exists := hippo.DirExists("/var/log")

// ensure that dir exists
exists, err := hippo.EnsureDir("/var/log", 755)

Latency Tracker Component

httpClient := hippo.NewHTTPClient()

latency := hippo.NewLatencyTracker()
latency.NewAction("api.call")

// First HTTP Call
start := time.Now()
httpClient.Get(
    "https://httpbin.org/get",
    map[string]string{},
    map[string]string{},
)
latency.SetPoint("api.call", start, time.Now())

// Another HTTP Call
latency.SetStart("api.call", time.Now())
httpClient.Get(
    "https://httpbin.org/get",
    map[string]string{},
    map[string]string{},
)
latency.SetEnd("api.call", time.Now())

// Now it will calculate the average
fmt.Println(latency.GetLatency("api.call"))
// Output 486.217112ms <nil>

Versioning

For transparency into our release cycle and in striving to maintain backward compatibility, Hippo is maintained under the Semantic Versioning guidelines and release process is predictable and business-friendly.

See the Releases section of our GitHub project for changelogs for each release version of Hippo. It contains summaries of the most noteworthy changes made in each release.

Bug tracker

If you have any suggestions, bug reports, or annoyances please report them to our issue tracker at https://github.com/clivern/hippo/issues

Security Issues

If you discover a security vulnerability within Hippo, please send an email to hello@clivern.com

Contributing

We are an open source, community-driven project so please feel free to join us. see the contributing guidelines for more details.

License

© 2019, Clivern. Released under MIT License.

Hippo is authored and maintained by @Clivern.

Documentation

Index

Constants

View Source
const (
	// ServiceUp const
	ServiceUp = "UP"
	// ServiceDown const
	ServiceDown = "DOWN"
	// ServiceUnknown const
	ServiceUnknown = "UNKNOWN"
)

Variables

This section is empty.

Functions

func CleanupCallers

func CleanupCallers(cleanAfter time.Duration)

CleanupCallers cleans old clients

func DirExists added in v1.4.0

func DirExists(path string) bool

DirExists reports whether the dir exists

func EnsureDir added in v1.5.2

func EnsureDir(dirName string, mode int) (bool, error)

EnsureDir ensures that directory exists

func FileExists added in v1.4.0

func FileExists(path string) bool

FileExists reports whether the named file exists

func HTTPCheck

func HTTPCheck(ctx context.Context, serviceName, URL string, parameters map[string]string, headers map[string]string) (bool, error)

HTTPCheck do HTTP health check

func NewCallerLimiter

func NewCallerLimiter(identifier string, eventsRate rate.Limit, tokenBurst int) *rate.Limiter

NewCallerLimiter create a new rate limiter with an identifier

func NewLogger added in v1.3.0

func NewLogger(level, encoding string, outputPaths []string) (*zap.Logger, error)

NewLogger returns a logger instance

func PathExists added in v1.4.0

func PathExists(path string) bool

PathExists reports whether the path exists

func PkgName

func PkgName() string

PkgName returns the package name

func RedisCheck

func RedisCheck(serviceName string, addr string, password string, db int) (bool, error)

RedisCheck do a redis health check

Types

type Check

type Check struct {
	ID     string `json:"id"`
	Status string `json:"status"`
	Error  string `json:"error"`
	Result bool   `json:"result"`
	// contains filtered or unexported fields
}

Check struct

type Clock

type Clock struct {
}

Clock Type

func (*Clock) Now

func (c *Clock) Now() time.Time

Now get current time

func (*Clock) Sleep

func (c *Clock) Sleep(d time.Duration)

Sleep sleeps for a time

type ConsulConfig

type ConsulConfig struct {
	URL     string
	Version string
}

ConsulConfig struct

type ConsulKv

type ConsulKv struct {
	Config ConsulConfig
}

ConsulKv struct

func (*ConsulKv) Delete

func (c *ConsulKv) Delete(ctx context.Context, key string, parameters map[string]string) (string, error)

Delete deletes a kv

func (*ConsulKv) Read

func (c *ConsulKv) Read(ctx context.Context, key string, parameters map[string]string) (string, error)

Read gets a kv

func (*ConsulKv) Update

func (c *ConsulKv) Update(ctx context.Context, key string, value string, parameters map[string]string) (string, error)

Update update or create a kv

type ConsulStatus

type ConsulStatus struct {
	Config ConsulConfig
}

ConsulStatus struct

func (*ConsulStatus) GetRaftLeader

func (c *ConsulStatus) GetRaftLeader(ctx context.Context, parameters map[string]string) (string, error)

GetRaftLeader returns the Raft leader for the datacenter in which the agent is running

func (*ConsulStatus) ListRaftPeers

func (c *ConsulStatus) ListRaftPeers(ctx context.Context, parameters map[string]string) (string, error)

ListRaftPeers retrieves the Raft peers for the datacenter in which the the agent is running

type Correlation

type Correlation interface {
	UUIDv4() string
}

Correlation interface

func NewCorrelation

func NewCorrelation() Correlation

NewCorrelation creates an instance of correlation struct

type HTTPClient

type HTTPClient interface {
	Get(ctx context.Context, endpoint string, parameters map[string]string, headers map[string]string) (*http.Response, error)
	Post(ctx context.Context, endpoint string, data string, parameters map[string]string, headers map[string]string) (*http.Response, error)
	Put(ctx context.Context, endpoint string, data string, parameters map[string]string, headers map[string]string) (*http.Response, error)
	Delete(ctx context.Context, endpoint string, parameters map[string]string, headers map[string]string) (*http.Response, error)
	BuildParameters(endpoint string, parameters map[string]string) (string, error)
	ToString(response *http.Response) (string, error)
	BuildData(parameters map[string]string) string
	GetStatusCode(response *http.Response) int
}

HTTPClient interface

func NewHTTPClient

func NewHTTPClient() HTTPClient

NewHTTPClient creates an instance of http client

type Health

type Health struct {
	Status string
	Checks []*Check
}

Health struct

func NewHealthChecker

func NewHealthChecker() *Health

NewHealthChecker initializes a new health checker

func (*Health) AddCheck

func (h *Health) AddCheck(ID string, callable func() (bool, error))

AddCheck adds a new check

func (*Health) ChecksReport

func (h *Health) ChecksReport() (string, error)

ChecksReport get checks Status

func (*Health) ChecksStatus

func (h *Health) ChecksStatus() string

ChecksStatus get checks Status

func (*Health) Down

func (h *Health) Down() *Health

Down set the Status to Down

func (*Health) IsDown

func (h *Health) IsDown() bool

IsDown returns true if Status is Down

func (*Health) IsUnknown

func (h *Health) IsUnknown() bool

IsUnknown returns true if Status is Unknown

func (*Health) IsUp

func (h *Health) IsUp() bool

IsUp returns true if Status is Up

func (*Health) RunChecks

func (h *Health) RunChecks()

RunChecks runs all health checks

func (*Health) Unknown

func (h *Health) Unknown() *Health

Unknown set the Status to Unknown

func (*Health) Up

func (h *Health) Up() *Health

Up set the Status to Up

type Latency added in v1.5.0

type Latency struct {
	Actions map[string][]Point
}

Latency struct

func NewLatencyTracker added in v1.5.0

func NewLatencyTracker() *Latency

NewLatencyTracker creates a new latency instance

func (*Latency) GetLatency added in v1.5.0

func (l *Latency) GetLatency(name string) (time.Duration, error)

GetLatency returns average latency in nanoseconds for specific action

func (*Latency) NewAction added in v1.5.0

func (l *Latency) NewAction(name string)

NewAction creates a new action tracking bucket

func (*Latency) SetEnd added in v1.5.0

func (l *Latency) SetEnd(name string, end time.Time) bool

SetEnd adds point end time

func (*Latency) SetPoint added in v1.5.0

func (l *Latency) SetPoint(name string, start, end time.Time)

SetPoint adds a new point

func (*Latency) SetStart added in v1.5.0

func (l *Latency) SetStart(name string, start time.Time) bool

SetStart adds point start time

type Message

type Message struct {
	Channel string
	Payload string
}

Message item

type Metric

type Metric struct {
	Name      string
	Value     string
	Timestamp int64
}

Metric struct

func NewMetric

func NewMetric(name, value string, timestamp int64) Metric

NewMetric creates a new metric

func NewMetrics

func NewMetrics(name, value string, timestamp int64) []Metric

NewMetrics creates a new metrics array

func (Metric) String

func (metric Metric) String() string

String transfer the metric to string

type Point added in v1.5.0

type Point struct {
	Start time.Time
	End   time.Time
}

Point struct

func (*Point) GetLatency added in v1.5.0

func (p *Point) GetLatency() time.Duration

GetLatency returns latency in nanoseconds

type ProcessLimiter

type ProcessLimiter interface {
	// Take should block to make sure that the RPS is met.
	Take() time.Time
}

ProcessLimiter interface

func NewProcessLimiter

func NewProcessLimiter(rate int) ProcessLimiter

NewProcessLimiter create a new process rate limiter

type Redis

type Redis struct {
	Client   *redis.Client
	Addr     string
	Password string
	DB       int
}

Redis driver

func NewRedisDriver

func NewRedisDriver(addr string, password string, db int) *Redis

NewRedisDriver create a new instance

func (*Redis) Connect

func (r *Redis) Connect() (bool, error)

Connect establish a redis connection

func (*Redis) Del

func (r *Redis) Del(key string) (int64, error)

Del deletes a record

func (*Redis) Exists

func (r *Redis) Exists(key string) (bool, error)

Exists deletes a record

func (*Redis) Get

func (r *Redis) Get(key string) (string, error)

Get gets a record value

func (*Redis) HDel

func (r *Redis) HDel(key, field string) (int64, error)

HDel deletes a hash record

func (*Redis) HExists

func (r *Redis) HExists(key, field string) (bool, error)

HExists checks if key exists on a hash

func (*Redis) HGet

func (r *Redis) HGet(key, field string) (string, error)

HGet gets a record from hash

func (*Redis) HLen

func (r *Redis) HLen(key string) (int64, error)

HLen count hash records

func (*Redis) HScan

func (r *Redis) HScan(key string, cursor uint64, match string, count int64) *redis.ScanCmd

HScan return an iterative obj for a hash

func (*Redis) HSet

func (r *Redis) HSet(key, field, value string) (bool, error)

HSet sets a record in hash

func (*Redis) HTruncate

func (r *Redis) HTruncate(key string) (int64, error)

HTruncate deletes a hash

func (*Redis) Ping

func (r *Redis) Ping() (bool, error)

Ping checks the redis connection

func (*Redis) Publish

func (r *Redis) Publish(channel string, message string) (bool, error)

Publish sends a message to channel

func (*Redis) Set

func (r *Redis) Set(key, value string, expiration time.Duration) (bool, error)

Set sets a record

func (*Redis) Subscribe

func (r *Redis) Subscribe(channel string, callback func(message Message) error) error

Subscribe listens to a channel

type SystemStats

type SystemStats struct {
	EnableCPU bool
	EnableMem bool
	EnableGC  bool
	StartTime time.Time
	Stats     map[string]uint64
}

SystemStats stuct

func NewSystemStats

func NewSystemStats(enableCPU, enableMem, enableGC bool) *SystemStats

NewSystemStats creates a new SystemStats

func (*SystemStats) Collect

func (s *SystemStats) Collect()

Collect collects enabled stats

func (*SystemStats) GetStats

func (s *SystemStats) GetStats() map[string]uint64

GetStats get stats list

type Task

type Task struct {
	Err    error
	Result string
	// contains filtered or unexported fields
}

Task struct

func NewTask

func NewTask(f func() (string, error)) *Task

NewTask initializes a new task based on a given work

func (*Task) Run

func (t *Task) Run(wg *sync.WaitGroup)

Run runs a Task

type TimeSeries

type TimeSeries interface {
	Connect() error
	Disconnect() error
	SendMetrics(metrics []Metric) error
	SendMetric(metric Metric) error
	IsNop() bool
}

TimeSeries interface

func NewGraphite

func NewGraphite(protocol string, host string, port int, prefix string) TimeSeries

NewGraphite create instance of graphite

type WorkersPool

type WorkersPool struct {
	Tasks []*Task
	// contains filtered or unexported fields
}

WorkersPool struct

func NewWorkersPool

func NewWorkersPool(tasks []*Task, concurrency int) *WorkersPool

NewWorkersPool initializes a new pool with the given tasks

func (*WorkersPool) Run

func (w *WorkersPool) Run()

Run runs all work within the pool and blocks until it's finished.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL