pm2io

package module
v0.0.1 Latest Latest
Warning

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

Go to latest
Published: Apr 23, 2019 License: MIT Imports: 8 Imported by: 2

README

PM2/io APM Golang

This PM2 module is standalone and must include a public/private key to working properly with PM2 Plus.

Init

package main

import (
  "github.com/keymetrics/pm2-io-apm-go/services"
  "github.com/keymetrics/pm2-io-apm-go/structures"
)

func main() {
  // Create PM2 connector
  pm2 := pm2io.Pm2Io{
    Config: &structures.Config{
      PublicKey:  "myPublic",
      PrivateKey: "myPrivate",
      Name:       "Golang app",
    },
  }
  
  // Add an action who can be triggered from PM2 Plus
  services.AddAction(&structures.Action{
    ActionName: "Get env",
    Callback: func(_ map[string]interface{}) string {
      return strings.Join(os.Environ(), "\n")
    },
  })
  
  // Add a function metric who will be aggregated
  nbd := structures.CreateFuncMetric("Function metric", "metric", "stable/integer", func() float64 {
    // For a FuncMetric, this will be called every ~1sec
    return float64(10)
  })
  services.AddMetric(&nbd)
  
  // Add a normal metric
  nbreq := structures.CreateMetric("Incrementable", "metric", "increments")
  services.AddMetric(&nbreq)

  // Goroutine who increment the value each 4 seconds
  go func() {
    ticker := time.NewTicker(4 * time.Second)
    for {
      <-ticker.C
      nbreq.Value++

      // Log to PM2 Plus
      pm2io.Notifier.Log("Value incremented")
    }
  }()

  // Start the connection to PM2 Plus servers
  pm2.Start()

  // Log that we started the program (optional, just for example)
  pm2io.Notifier.Log("Started")
  
  // Wait infinitely (for example)
  <-time.After(time.Duration(math.MaxInt64))
}

Send error then panic

You can send an error to PM2 Plus before panic your program

name, err := os.Hostname()
if err != nil {
  pm2io.Panic(err)
  // The program will crash with panic just after the message is sent
}

Use a proxy for APM requests and WebSocket

  pm2io.Pm2Io{
    Config: &structures.Config{
      PublicKey:  "myPublic",
      PrivateKey: "myPrivate",
      Name:       "Golang app",
      Proxy:      "socks5://localhost:1080/",
    },
  }

Connect logrus to PM2 Plus

If you are using logrus, this is an example to send logs and create exceptions on PM2 Plus when you log an error

package main

import (
  pm2io "github.com/keymetrics/pm2-io-apm-go"
  "github.com/sirupsen/logrus"
)

// HookLog will send logs to PM2 Plus
type HookLog struct {
  Pm2 *pm2io.Pm2Io
}

// HookErr will send all errors to PM2 Plus
type HookErr struct {
  Pm2 *pm2io.Pm2Io
}

// Fire event
func (hook *HookLog) Fire(e *logrus.Entry) error {
  str, err := e.String()
  if err == nil {
    hook.Pm2.Notifier.Log(str)
  }
  return err
}

// Levels for all possible logs
func (*HookLog) Levels() []logrus.Level {
  return logrus.AllLevels
}

// Fire an error and notify it as exception
func (hook *HookErr) Fire(e *logrus.Entry) error {
  if err, ok := e.Data["error"].(error); ok {
    hook.Pm2.Notifier.Error(err)
  }
  return nil
}

// Levels only for errors
func (*HookErr) Levels() []logrus.Level {
  return []logrus.Level{logrus.ErrorLevel}
}

func main() {
  pm2 := pm2io.Pm2Io{
    Config: &structures.Config{
      PublicKey:  "myPublic",
      PrivateKey: "myPrivate",
      Name:       "Golang app",
    },
  }

  logrus.AddHook(&HookLog{
    Pm2: pm2,
  })
  logrus.AddHook(&HookErr{
    Pm2: pm2,
  })
}

Distributed Tracing

NB: you must pass the same context.Context to your subfuncs (same traceID). It's very useful when you want the same trace for HTTP spans and your database spans

More informations on OpenCensus

HTTP

OpenCensus will create another handler with wrapped functions. It's important to use contexts everytime

For client and server, it use B3 for communication by default

OpenCensus Documentation about ochttp

import (
  "net/http"

  "go.opencensus.io/plugin/ochttp"
)

handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  context := r.Context()
  // Not used here, but you must pass it to lower functions (espacially databases one)

  log.Println("request")
  for i := 0; i < 1000; i++ {
    fmt.Fprintf(w, "Hello")
  }
})

ocHandler := &ochttp.Handler{Handler: handler, IsPublicEndpoint: true}
http.ListenAndServe(":8089", ocHandler)
Mongo

With MongoDB wrapper you have to use a context, do don't create a new one and use the first one created

OpenCensus Documentation about mongowrapper

SQL

You can use it by registration or wrapping, here we use the first one

NB: if you have some ocsql.warning, try to update your dependency

OpenCensus Documentation about ocsql

import (
  "database/sql"

  "contrib.go.opencensus.io/integrations/ocsql"
)

// Create a new driver registred with OpenCensus
driverName, err := ocsql.Register("postgres", ocsql.WithOptions(ocsql.TraceOptions{
  AllowRoot:    true,
  Ping:         true,
  RowsNext:     false,
  RowsClose:    false,
  RowsAffected: true,
  LastInsertID: true,
  Query:        true,
  QueryParams:  false, // Don't send value of $1, $2... args
}))
if err != nil {
  log.Fatalf("Failed to register the ocsql driver: %v", err)
  return
}

// Then use the OpenCensus driver as usual
db, err := sql.Open(driverName, fmt.Sprintf(
  "user=%s password=%s dbname=%s host=%s port=%s sslmode=disable",
  cfg.User, cfg.Password, cfg.Database, cfg.Host, cfg.Port))
if err != nil {
  err = errors.Wrapf(err,
    "Couldn't open connection to postgre database",
  )
  return
}

// Use QueryContext for each query
func DeleteThings(ctx context.Context) error {
  q, err := db.QueryContext(ctx, "DROP TABLE things;")
	q.Close()
	return err
}
Other integrations

We didn't test others integrations, but everything compatible with OpenCensus/Zipkin should work without any problem

Known problems

x509: unknown authority

You must have the Let's Encrypt Authority X3 certificate on your machine/container to connect to our backend

Alpine based container
apk add -U --no-cache ca-certificates
Debian based container
apt-get install -y ca-certificates

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Pm2Io

type Pm2Io struct {
	Config *structures.Config

	Notifier *features.Notifier

	StatusOverrider func() *structures.Status
	// contains filtered or unexported fields
}

Pm2Io to config and access all services

func (*Pm2Io) Panic

func (pm2io *Pm2Io) Panic(err error)

Panic notify KM then panic

func (*Pm2Io) RestartTransporter

func (pm2io *Pm2Io) RestartTransporter()

RestartTransporter including webSocket connection

func (*Pm2Io) SendStatus

func (pm2io *Pm2Io) SendStatus()

SendStatus of current state

func (*Pm2Io) Start

func (pm2io *Pm2Io) Start()

Start and prepare services + profiling

func (*Pm2Io) StartTracing

func (pm2io *Pm2Io) StartTracing() error

StartTracing add global handlers for OpenCensus providers

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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