Merge branch 'Xe/fix/update-ln' of xena/route into master
This commit is contained in:
commit
334f483574
|
@ -31,6 +31,7 @@ var allScopes = []string{
|
||||||
"token:get", "token:getall", "token:put", "token:delete", "token:deactivate",
|
"token:get", "token:getall", "token:put", "token:delete", "token:deactivate",
|
||||||
"route:get", "route:getall", "route:put", "route:delete",
|
"route:get", "route:getall", "route:put", "route:delete",
|
||||||
"connect",
|
"connect",
|
||||||
|
"admin",
|
||||||
}
|
}
|
||||||
|
|
||||||
var whoami string
|
var whoami string
|
||||||
|
@ -123,10 +124,21 @@ func handle(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
cmdline := kingpin.MustParse(app.Parse(os.Args[1:]))
|
cmdline := kingpin.MustParse(app.Parse(os.Args[1:]))
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
retry_netrc:
|
||||||
n, err := netrc.Parse(*netrcPath)
|
n, err := netrc.Parse(*netrcPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ln.Fatal(ln.F{"err": err, "action": "netrc.Parse"})
|
_, err := os.Stat(*netrcPath)
|
||||||
|
if err == os.ErrNotExist {
|
||||||
|
fout, err := os.Create(*netrcPath)
|
||||||
|
if err != nil {
|
||||||
|
ln.FatalErr(ctx, err, ln.Action("creating netrc"), ln.F{"path": *netrcPath})
|
||||||
|
}
|
||||||
|
fout.Close()
|
||||||
|
goto retry_netrc
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ = n
|
_ = n
|
||||||
|
|
||||||
|
@ -134,30 +146,35 @@ func main() {
|
||||||
case "test-server":
|
case "test-server":
|
||||||
http.HandleFunc("/", handle)
|
http.HandleFunc("/", handle)
|
||||||
|
|
||||||
ln.Fatal(ln.F{"err": http.ListenAndServe(*testServerAddr, nil), "action": "test_server"})
|
ln.FatalErr(ctx, http.ListenAndServe(*testServerAddr, nil), ln.Action("test server listenAndServe"))
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
case "generate-key":
|
case "generate-key":
|
||||||
key, err := routecrypto.GenerateKey()
|
key, err := routecrypto.GenerateKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ln.Fatal(ln.F{"err": err, "action": "routecrypto.GenerateKey"})
|
ln.FatalErr(ctx, err, ln.Action("generating encryption key"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Your key is:", routecrypto.ShowKey(key))
|
fmt.Println("Your key is:", routecrypto.ShowKey(key))
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
case "token generate-root":
|
case "token generate-root":
|
||||||
key, err := routecrypto.ParseKey(*tokenGenerateKey)
|
key, err := routecrypto.ParseKey(*tokenGenerateKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ln.Fatal(ln.F{"err": err, "action": "routecrypto.ParseKey"})
|
ln.FatalErr(ctx, err, ln.Action("parsing encryption key"))
|
||||||
}
|
}
|
||||||
db, err := database.NewBoltStorage(*tokenGenerateDatabasePath, key)
|
db, err := database.NewBoltStorage(*tokenGenerateDatabasePath, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ln.Fatal(ln.F{"err": err, "action": "database.NewBoltStorage"})
|
ln.FatalErr(ctx, err, ln.Action("opening routed database"))
|
||||||
}
|
}
|
||||||
|
|
||||||
tBody := uuid.New()
|
tBody := uuid.New()
|
||||||
|
|
||||||
_, err = db.PutToken(context.Background(), tBody, *tokenGenerateUsername, *tokenGenerateScopes)
|
_, err = db.PutToken(context.Background(), tBody, *tokenGenerateUsername, *tokenGenerateScopes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ln.Fatal(ln.F{"err": err, "action": "db.PutToken"})
|
ln.FatalErr(ctx, err, ln.Action("add newly created token to database"))
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
|
@ -166,7 +183,7 @@ func main() {
|
||||||
n.AddMachine(*grpcServer, *tokenGenerateUsername, tBody)
|
n.AddMachine(*grpcServer, *tokenGenerateUsername, tBody)
|
||||||
err = n.Save()
|
err = n.Save()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ln.Fatal(ln.F{"err": err, "action": "n.Save"})
|
ln.FatalErr(ctx, err, ln.Action("add machine to netrc"))
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -182,7 +199,7 @@ func main() {
|
||||||
grpc.WithTransportCredentials(connCreds),
|
grpc.WithTransportCredentials(connCreds),
|
||||||
grpc.WithPerRPCCredentials(creds))
|
grpc.WithPerRPCCredentials(creds))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ln.Fatal(ln.F{"err": err, "action": "grpc.Dial"})
|
ln.FatalErr(ctx, err, ln.Action("dialing grpc server"), ln.F{"hostname": *grpcServer})
|
||||||
}
|
}
|
||||||
|
|
||||||
rc := proto.NewRoutesClient(conn)
|
rc := proto.NewRoutesClient(conn)
|
||||||
|
@ -195,19 +212,21 @@ func main() {
|
||||||
|
|
||||||
switch cmdline {
|
switch cmdline {
|
||||||
case "route create":
|
case "route create":
|
||||||
idr, err := rc.Put(context.Background(), &proto.Route{Host: *routesCreateDomain})
|
idr, err := rc.Put(ctx, &proto.Route{Host: *routesCreateDomain})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ln.Fatal(ln.F{"err": err, "action": "rc.Put"})
|
ln.FatalErr(ctx, err, ln.Action("create new route"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(idr.Id)
|
fmt.Println("created route with id " + idr.Id)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
case "route inspect":
|
case "route inspect":
|
||||||
r, err := rc.Get(context.Background(), &proto.GetRouteRequest{
|
r, err := rc.Get(context.Background(), &proto.GetRouteRequest{
|
||||||
Host: *routesCreateDomain,
|
Host: *routesCreateDomain,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ln.Fatal(ln.F{"err": err, "action": "rc.Get"})
|
ln.FatalErr(ctx, err, ln.Action("get single route"), ln.F{"domain": *routesCreateDomain})
|
||||||
}
|
}
|
||||||
|
|
||||||
json.NewEncoder(os.Stdout).Encode(r)
|
json.NewEncoder(os.Stdout).Encode(r)
|
||||||
|
@ -218,7 +237,7 @@ func main() {
|
||||||
case "route list":
|
case "route list":
|
||||||
rts, err := rc.GetAll(context.Background(), &proto.Nil{})
|
rts, err := rc.GetAll(context.Background(), &proto.Nil{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ln.Fatal(ln.F{"err": err, "action": "rc.GetAll"})
|
ln.FatalErr(ctx, err, ln.Action("get all routes"))
|
||||||
}
|
}
|
||||||
|
|
||||||
table := tablewriter.NewWriter(os.Stdout)
|
table := tablewriter.NewWriter(os.Stdout)
|
||||||
|
@ -235,16 +254,18 @@ func main() {
|
||||||
case "route rm":
|
case "route rm":
|
||||||
_, err := rc.Delete(context.Background(), &proto.Route{Id: *routesRmID})
|
_, err := rc.Delete(context.Background(), &proto.Route{Id: *routesRmID})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ln.Fatal(ln.F{"err": err, "action": "rc.Delete"})
|
ln.FatalErr(ctx, err, ln.Action("remove single route"), ln.F{"id": *routesRmID})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
case "backend list":
|
case "backend list":
|
||||||
bkds, err := bc.List(context.Background(), &proto.BackendSelector{
|
bkds, err := bc.List(context.Background(), &proto.BackendSelector{
|
||||||
Domain: *backendListDomain,
|
Domain: *backendListDomain,
|
||||||
User: *backendListUser,
|
User: *backendListUser,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ln.Fatal(ln.F{"err": err, "action": "list backends"})
|
ln.FatalErr(ctx, err, ln.Action("list backends"))
|
||||||
}
|
}
|
||||||
|
|
||||||
table := tablewriter.NewWriter(os.Stdout)
|
table := tablewriter.NewWriter(os.Stdout)
|
||||||
|
@ -256,12 +277,51 @@ func main() {
|
||||||
|
|
||||||
table.Render()
|
table.Render()
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
case "backend kill":
|
case "backend kill":
|
||||||
_, err := bc.Kill(context.Background(), &proto.BackendID{Id: *backendKillID})
|
_, err := bc.Kill(context.Background(), &proto.BackendID{Id: *backendKillID})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ln.Fatal(ln.F{"err": err, "action": "attempt to kill backend", "backend_id": *backendKillID})
|
ln.FatalErr(ctx, err, ln.Action("attempt to kill backend"), ln.F{"backend_id": *backendKillID})
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("killed backend " + *backendKillID)
|
fmt.Println("killed backend " + *backendKillID)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
case "token list":
|
||||||
|
lis, err := tc.GetAll(ctx, &proto.Nil{})
|
||||||
|
if err != nil {
|
||||||
|
ln.FatalErr(ctx, err, ln.Action("get all tokens"))
|
||||||
|
}
|
||||||
|
|
||||||
|
table := tablewriter.NewWriter(os.Stdout)
|
||||||
|
table.SetHeader([]string{"ID", "Active", "Scopes"})
|
||||||
|
|
||||||
|
for _, tkn := range lis.Tokens {
|
||||||
|
table.Append([]string{tkn.Id, fmt.Sprint(tkn.Active), fmt.Sprint(tkn.Scopes)})
|
||||||
|
}
|
||||||
|
|
||||||
|
table.Render()
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
case "token create":
|
||||||
|
scps := *tokenCreateScopes
|
||||||
|
tkn := &proto.Token{
|
||||||
|
Scopes: scps,
|
||||||
|
}
|
||||||
|
|
||||||
|
ftkn, err := tc.Put(ctx, tkn)
|
||||||
|
if err != nil {
|
||||||
|
ln.FatalErr(ctx, err, ln.Action("put token to server"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Your token is: %s\n", ftkn.Body)
|
||||||
|
fmt.Printf("It has permission for the following scopes: %v\n", ftkn.Scopes)
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ln.Fatal(ctx, ln.Action("not implemented"), ln.F{"command": cmdline})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"flag"
|
"flag"
|
||||||
"os"
|
|
||||||
|
|
||||||
"git.xeserv.us/xena/route/lib/tun2"
|
"git.xeserv.us/xena/route/lib/tun2"
|
||||||
"github.com/Xe/ln"
|
"github.com/Xe/ln"
|
||||||
|
@ -34,9 +34,6 @@ func main() {
|
||||||
client, _ := tun2.NewClient(cfg)
|
client, _ := tun2.NewClient(cfg)
|
||||||
err := client.Connect()
|
err := client.Connect()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ln.Error(err, ln.F{
|
ln.FatalErr(context.Background(), err, ln.Action("http agent is now running"))
|
||||||
"action": "client_running",
|
|
||||||
})
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"flag"
|
"flag"
|
||||||
"log"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
_ "git.xeserv.us/xena/route/internal"
|
||||||
|
"git.xeserv.us/xena/route/internal/middleware"
|
||||||
"git.xeserv.us/xena/route/internal/routecrypto"
|
"git.xeserv.us/xena/route/internal/routecrypto"
|
||||||
"git.xeserv.us/xena/route/internal/server"
|
"git.xeserv.us/xena/route/internal/server"
|
||||||
"github.com/Xe/ln"
|
"github.com/Xe/ln"
|
||||||
|
@ -25,31 +27,34 @@ func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
flagenv.Parse()
|
flagenv.Parse()
|
||||||
rand.Seed(time.Now().Unix())
|
rand.Seed(time.Now().Unix())
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
certKey, _ := routecrypto.ParseKey(*sslCertKey)
|
certKey, _ := routecrypto.ParseKey(*sslCertKey)
|
||||||
|
|
||||||
scfg := server.Config{}
|
scfg := server.Config{}
|
||||||
err := env.Parse(&scfg)
|
err := env.Parse(&scfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ln.Fatal(ln.F{"err": err, "action": "env.Parse()"})
|
ln.FatalErr(ctx, err, ln.Action("parsing environment for config"))
|
||||||
}
|
}
|
||||||
scfg.CertKey = certKey
|
scfg.CertKey = certKey
|
||||||
|
|
||||||
s, err := server.New(scfg)
|
s, err := server.New(scfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
ln.FatalErr(ctx, err, ln.Action("create server instance"))
|
||||||
}
|
}
|
||||||
|
|
||||||
go setupTLS(s, scfg)
|
go setupTLS(s, scfg)
|
||||||
|
|
||||||
|
// listen on HTTP listener
|
||||||
l, err := net.Listen("tcp", scfg.WebAddr)
|
l, err := net.Listen("tcp", scfg.WebAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
ln.FatalErr(ctx, err, ln.Action("listening on HTTP port"), ln.F{"addr": scfg.WebAddr})
|
||||||
}
|
}
|
||||||
defer l.Close()
|
defer l.Close()
|
||||||
|
|
||||||
hs := &http.Server{
|
hs := &http.Server{
|
||||||
Handler: s,
|
Handler: middleware.Trace(s),
|
||||||
Addr: scfg.WebAddr,
|
Addr: scfg.WebAddr,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,12 +63,14 @@ func main() {
|
||||||
|
|
||||||
func setupTLS(s *server.Server, scfg server.Config) {
|
func setupTLS(s *server.Server, scfg server.Config) {
|
||||||
hs := &http.Server{
|
hs := &http.Server{
|
||||||
Handler: s,
|
Handler: middleware.Trace(s),
|
||||||
Addr: scfg.SSLAddr,
|
Addr: scfg.SSLAddr,
|
||||||
TLSConfig: &tls.Config{
|
TLSConfig: &tls.Config{
|
||||||
GetCertificate: s.GetCertificate,
|
GetCertificate: s.GetCertificate,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
hs.ListenAndServeTLS("", "")
|
for {
|
||||||
|
hs.ListenAndServeTLS("", "")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ func (b *BoltDBStorage) GetRoute(ctx context.Context, host string) (Route, error
|
||||||
r := Route{}
|
r := Route{}
|
||||||
err := b.db.One("Hostname", host, &r)
|
err := b.db.One("Hostname", host, &r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ln.Error(err, ln.F{"err": err, "action": "route_get_route"})
|
ln.Error(ctx, err, ln.F{"err": err, "action": "route_get_route"})
|
||||||
|
|
||||||
switch err {
|
switch err {
|
||||||
case storm.ErrNotFound:
|
case storm.ErrNotFound:
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package internal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
|
@ -0,0 +1,11 @@
|
||||||
|
// Package internal contains autoloading packages and tools.
|
||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Xe/ln"
|
||||||
|
"github.com/Xe/ln/ex"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
ln.DefaultLogger.Filters = append(ln.DefaultLogger.Filters, ex.NewGoTraceLogger())
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/rpc"
|
||||||
|
|
||||||
|
// Add HTTP pprof routes
|
||||||
|
_ "net/http/pprof"
|
||||||
|
|
||||||
|
// Add tracing routes
|
||||||
|
_ "golang.org/x/net/trace"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
l, err := net.Listen("tcp", "127.0.0.1:0")
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("manhole: cannot bind to 127.0.0.1:0: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("manhole: Now listening on http://%s", l.Addr())
|
||||||
|
|
||||||
|
rpc.HandleHTTP()
|
||||||
|
go http.Serve(l, nil)
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Xe/ln"
|
||||||
|
"golang.org/x/net/trace"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Trace adds go stdlib tracing to this http handler.
|
||||||
|
func Trace(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
sp := trace.New(filepath.Base(os.Args[0]), "http://"+r.Host+r.RequestURI)
|
||||||
|
defer sp.Finish()
|
||||||
|
ctx, cancel := context.WithTimeout(r.Context(), 30*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
ctx = trace.NewContext(ctx, sp)
|
||||||
|
f := ln.F{
|
||||||
|
"method": r.Method,
|
||||||
|
"path": r.URL.Path,
|
||||||
|
"remote_addr": r.RemoteAddr,
|
||||||
|
"user_agent": r.UserAgent(),
|
||||||
|
}
|
||||||
|
|
||||||
|
next.ServeHTTP(w, r.WithContext(ctx))
|
||||||
|
|
||||||
|
ws, ok := w.(interface {
|
||||||
|
Status() int
|
||||||
|
})
|
||||||
|
if ok {
|
||||||
|
f["status"] = ws.Status()
|
||||||
|
}
|
||||||
|
|
||||||
|
ln.Log(ctx, f)
|
||||||
|
})
|
||||||
|
}
|
|
@ -3,7 +3,9 @@ package server
|
||||||
import (
|
import (
|
||||||
"git.xeserv.us/xena/route/lib/tun2"
|
"git.xeserv.us/xena/route/lib/tun2"
|
||||||
proto "git.xeserv.us/xena/route/proto"
|
proto "git.xeserv.us/xena/route/proto"
|
||||||
|
"github.com/Xe/ln"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
"golang.org/x/net/trace"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Backend implements proto.BackendsServer for gRPC.
|
// Backend implements proto.BackendsServer for gRPC.
|
||||||
|
@ -13,6 +15,14 @@ type Backend struct {
|
||||||
|
|
||||||
// List returns a list of backends given filtering parameters.
|
// List returns a list of backends given filtering parameters.
|
||||||
func (b *Backend) List(ctx context.Context, sel *proto.BackendSelector) (*proto.BackendList, error) {
|
func (b *Backend) List(ctx context.Context, sel *proto.BackendSelector) (*proto.BackendList, error) {
|
||||||
|
ctx, clitok, err := b.getAuth(ctx, "backend list", "backend:list")
|
||||||
|
if err != nil {
|
||||||
|
return nil, handleError(ctx, clitok, err, ln.F{"action": "authentication for backend list"})
|
||||||
|
}
|
||||||
|
|
||||||
|
tr, _ := trace.FromContext(ctx)
|
||||||
|
defer tr.Finish()
|
||||||
|
|
||||||
bl := map[string]tun2.Backend{}
|
bl := map[string]tun2.Backend{}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
@ -51,9 +61,19 @@ func (b *Backend) List(ctx context.Context, sel *proto.BackendSelector) (*proto.
|
||||||
|
|
||||||
// Kill removes a backend's connection by ID.
|
// Kill removes a backend's connection by ID.
|
||||||
func (b *Backend) Kill(ctx context.Context, bid *proto.BackendID) (*proto.Nil, error) {
|
func (b *Backend) Kill(ctx context.Context, bid *proto.BackendID) (*proto.Nil, error) {
|
||||||
if err := b.ts.KillBackend(bid.Id); err != nil {
|
ctx, clitok, err := b.getAuth(ctx, "backend list", "backend:list")
|
||||||
return nil, err
|
if err != nil {
|
||||||
|
return nil, handleError(ctx, clitok, err, ln.F{"action": "authentication for backend list"})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tr, _ := trace.FromContext(ctx)
|
||||||
|
defer tr.Finish()
|
||||||
|
|
||||||
|
if err := b.ts.KillBackend(bid.Id); err != nil {
|
||||||
|
return nil, handleError(ctx, clitok, err, ln.F{"action": "killing backend", "backend_id": bid.Id})
|
||||||
|
}
|
||||||
|
|
||||||
|
ln.Log(ctx, clitok, ln.Action("backend killed"), ln.F{"backend_id": bid.Id})
|
||||||
|
|
||||||
return &proto.Nil{}, nil
|
return &proto.Nil{}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
|
|
||||||
"git.xeserv.us/xena/route/internal/database"
|
"git.xeserv.us/xena/route/internal/database"
|
||||||
"github.com/Xe/ln"
|
"github.com/Xe/ln"
|
||||||
|
"golang.org/x/net/trace"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/metadata"
|
"google.golang.org/grpc/metadata"
|
||||||
|
@ -16,23 +17,23 @@ var (
|
||||||
ErrNotAuthorized = errors.New("server: not authorized")
|
ErrNotAuthorized = errors.New("server: not authorized")
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Server) getAuth(ctx context.Context, scope string) (database.Token, error) {
|
func (s *Server) getAuth(ctx context.Context, operation, scope string) (context.Context, database.Token, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
md, ok := metadata.FromIncomingContext(ctx)
|
md, ok := metadata.FromIncomingContext(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return database.Token{}, grpc.Errorf(codes.Unauthenticated, "valid token required.")
|
return nil, database.Token{}, grpc.Errorf(codes.Unauthenticated, "valid token required.")
|
||||||
}
|
}
|
||||||
|
|
||||||
jwtToken, ok := md["authorization"]
|
jwtToken, ok := md["authorization"]
|
||||||
if !ok {
|
if !ok {
|
||||||
return database.Token{}, grpc.Errorf(codes.Unauthenticated, "valid token required.")
|
return nil, database.Token{}, grpc.Errorf(codes.Unauthenticated, "valid token required.")
|
||||||
}
|
}
|
||||||
val := jwtToken[0]
|
val := jwtToken[0]
|
||||||
|
|
||||||
t, err := s.db.GetToken(ctx, val)
|
t, err := s.db.GetToken(ctx, val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return database.Token{}, grpc.Errorf(codes.Unauthenticated, "valid token required.")
|
return nil, database.Token{}, grpc.Errorf(codes.Unauthenticated, "valid token required.")
|
||||||
}
|
}
|
||||||
|
|
||||||
ok = false
|
ok = false
|
||||||
|
@ -42,14 +43,24 @@ func (s *Server) getAuth(ctx context.Context, scope string) (database.Token, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
return database.Token{}, grpc.Errorf(codes.Unauthenticated, "invalid scope.")
|
return nil, database.Token{}, grpc.Errorf(codes.Unauthenticated, "invalid scope.")
|
||||||
}
|
}
|
||||||
|
|
||||||
return t, nil
|
tr := trace.New("routed-grpc", operation)
|
||||||
|
ctx = trace.NewContext(ctx, tr)
|
||||||
|
|
||||||
|
return ctx, t, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleError(ctx context.Context, clitok database.Token, err error, f ln.F) error {
|
func handleError(ctx context.Context, clitok database.Token, err error, f ln.F) error {
|
||||||
ln.Error(err, f, clitok.F())
|
tr, ok := trace.FromContext(ctx)
|
||||||
|
if !ok {
|
||||||
|
goto skip
|
||||||
|
}
|
||||||
|
tr.SetError()
|
||||||
|
|
||||||
|
skip:
|
||||||
|
ln.Error(ctx, err, f, clitok)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
proto "git.xeserv.us/xena/route/proto"
|
proto "git.xeserv.us/xena/route/proto"
|
||||||
"github.com/Xe/ln"
|
"github.com/Xe/ln"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
"golang.org/x/net/trace"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Route implements rout.RoutesServer for gRPC
|
// Route implements rout.RoutesServer for gRPC
|
||||||
|
@ -19,16 +20,17 @@ var (
|
||||||
|
|
||||||
// Get fetches a route from the database.
|
// Get fetches a route from the database.
|
||||||
func (r *Route) Get(ctx context.Context, req *proto.GetRouteRequest) (*proto.Route, error) {
|
func (r *Route) Get(ctx context.Context, req *proto.GetRouteRequest) (*proto.Route, error) {
|
||||||
clitok, err := r.getAuth(ctx, "route:get")
|
ctx, clitok, err := r.getAuth(ctx, "get single route", "route:get")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, handleError(ctx, clitok, err, ln.F{"action": "Route.Get_getAuth"})
|
return nil, handleError(ctx, clitok, err, ln.F{"action": "Route.Get_getAuth"})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tr, _ := trace.FromContext(ctx)
|
||||||
|
defer tr.Finish()
|
||||||
|
|
||||||
val, err := r.db.GetRoute(ctx, req.Host)
|
val, err := r.db.GetRoute(ctx, req.Host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ln.Error(err, ln.F{"action": "Route.Get"})
|
return nil, handleError(ctx, clitok, err, ln.F{"action": "get single route from database", "host": req.Host})
|
||||||
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if val.Creator != clitok.Owner {
|
if val.Creator != clitok.Owner {
|
||||||
|
@ -40,16 +42,17 @@ func (r *Route) Get(ctx context.Context, req *proto.GetRouteRequest) (*proto.Rou
|
||||||
|
|
||||||
// GetAll fetches all of the routes that you own.
|
// GetAll fetches all of the routes that you own.
|
||||||
func (r *Route) GetAll(ctx context.Context, req *proto.Nil) (*proto.GetAllRoutesResponse, error) {
|
func (r *Route) GetAll(ctx context.Context, req *proto.Nil) (*proto.GetAllRoutesResponse, error) {
|
||||||
clitok, err := r.getAuth(ctx, "route:getall")
|
ctx, clitok, err := r.getAuth(ctx, "get all routes for user", "route:getall")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, handleError(ctx, clitok, err, ln.F{"action": "Route.GetAll_getAuth"})
|
return nil, handleError(ctx, clitok, err, ln.F{"action": "Route.GetAll_getAuth"})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tr, _ := trace.FromContext(ctx)
|
||||||
|
defer tr.Finish()
|
||||||
|
|
||||||
routes, err := r.db.GetAllRoutes(ctx, clitok.Owner)
|
routes, err := r.db.GetAllRoutes(ctx, clitok.Owner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ln.Error(err, ln.F{"action": "Route.GetAll"})
|
return nil, handleError(ctx, clitok, err, ln.F{"action": "get all routes for user from database"})
|
||||||
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result := []*proto.Route{}
|
result := []*proto.Route{}
|
||||||
|
@ -65,23 +68,24 @@ func (r *Route) GetAll(ctx context.Context, req *proto.Nil) (*proto.GetAllRoutes
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Route) Put(ctx context.Context, rt *proto.Route) (*proto.IDResponse, error) {
|
func (r *Route) Put(ctx context.Context, rt *proto.Route) (*proto.IDResponse, error) {
|
||||||
clitok, err := r.getAuth(ctx, "route:put")
|
ctx, clitok, err := r.getAuth(ctx, "put new route", "route:put")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, handleError(ctx, clitok, err, ln.F{"action": "Route.Put_getAuth"})
|
return nil, handleError(ctx, clitok, err, ln.F{"action": "Route.Put_getAuth"})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tr, _ := trace.FromContext(ctx)
|
||||||
|
defer tr.Finish()
|
||||||
|
|
||||||
if rt.Host == "" {
|
if rt.Host == "" {
|
||||||
rt.Host = elfs.MakeName() + r.cfg.DomainSuffix
|
rt.Host = elfs.MakeName() + r.cfg.DomainSuffix
|
||||||
}
|
}
|
||||||
|
|
||||||
drt, err := r.db.PutRoute(ctx, rt.Host, clitok.Owner)
|
drt, err := r.db.PutRoute(ctx, rt.Host, clitok.Owner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ln.Error(err, ln.F{"action": "Route.Put"})
|
return nil, handleError(ctx, clitok, err, ln.F{"action": "put route to database"})
|
||||||
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ln.Log(drt.F(), ln.F{"action": "Route.Put_success"})
|
ln.Log(ctx, drt, ln.Action("created new route"))
|
||||||
|
|
||||||
return &proto.IDResponse{
|
return &proto.IDResponse{
|
||||||
Id: drt.ID,
|
Id: drt.ID,
|
||||||
|
@ -89,30 +93,32 @@ func (r *Route) Put(ctx context.Context, rt *proto.Route) (*proto.IDResponse, er
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Route) Delete(ctx context.Context, rt *proto.Route) (*proto.IDResponse, error) {
|
func (r *Route) Delete(ctx context.Context, rt *proto.Route) (*proto.IDResponse, error) {
|
||||||
clitok, err := r.getAuth(ctx, "route:delete")
|
ctx, clitok, err := r.getAuth(ctx, "delete single route", "route:delete")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, handleError(ctx, clitok, err, ln.F{"action": "Route.Delete_getAuth"})
|
return nil, handleError(ctx, clitok, err, ln.F{"action": "Route.Delete_getAuth"})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tr, _ := trace.FromContext(ctx)
|
||||||
|
defer tr.Finish()
|
||||||
|
|
||||||
drt, err := r.db.GetRoute(ctx, rt.Host)
|
drt, err := r.db.GetRoute(ctx, rt.Host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ln.Error(err, ln.F{"action": "Route.Delete_getRoute_verify"})
|
return nil, handleError(ctx, clitok, err, ln.F{"action": "fetch route from database", "host": rt.Host})
|
||||||
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if drt.Creator != clitok.Owner {
|
if drt.Creator != clitok.Owner {
|
||||||
return nil, handleError(ctx, clitok, ErrNotAuthorized, ln.F{"action": "Route.Delete_not_authorized"})
|
return nil, handleError(ctx, clitok, ErrNotAuthorized, ln.F{"action": "user not authorized to delete this route", "host": rt.Host})
|
||||||
}
|
}
|
||||||
|
|
||||||
err = r.db.DeleteRoute(ctx, rt.Id)
|
err = r.db.DeleteRoute(ctx, rt.Id)
|
||||||
f := drt.F()
|
f := drt.F()
|
||||||
f["action"] = "Route.Delete_db.DeleteRoute"
|
f["action"] = "delete route from database"
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handleError(ctx, clitok, ErrNotAuthorized, f)
|
handleError(ctx, clitok, ErrNotAuthorized, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
ln.Log(f, drt.F())
|
f["action"] = "deleted route from database"
|
||||||
|
ln.Log(ctx, f, drt)
|
||||||
|
|
||||||
return &proto.IDResponse{Id: rt.Id}, nil
|
return &proto.IDResponse{Id: rt.Id}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"github.com/Xe/ln"
|
"github.com/Xe/ln"
|
||||||
"github.com/Xe/uuid"
|
"github.com/Xe/uuid"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
"golang.org/x/net/trace"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
)
|
)
|
||||||
|
@ -20,11 +21,14 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (t *Token) Get(ctx context.Context, req *proto.GetTokenRequest) (*proto.Token, error) {
|
func (t *Token) Get(ctx context.Context, req *proto.GetTokenRequest) (*proto.Token, error) {
|
||||||
clitok, err := t.getAuth(ctx, "token:get")
|
ctx, clitok, err := t.getAuth(ctx, "get single token", "token:get")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, handleError(ctx, clitok, err, ln.F{"action": "Token.Get_getAuth"})
|
return nil, handleError(ctx, clitok, err, ln.F{"action": "not authorized"})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tr, _ := trace.FromContext(ctx)
|
||||||
|
defer tr.Finish()
|
||||||
|
|
||||||
if req.Id == "" {
|
if req.Id == "" {
|
||||||
return nil, status.Errorf(codes.InvalidArgument, "must specify ID")
|
return nil, status.Errorf(codes.InvalidArgument, "must specify ID")
|
||||||
}
|
}
|
||||||
|
@ -42,11 +46,14 @@ func (t *Token) Get(ctx context.Context, req *proto.GetTokenRequest) (*proto.Tok
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Token) GetAll(ctx context.Context, req *proto.Nil) (*proto.TokenSet, error) {
|
func (t *Token) GetAll(ctx context.Context, req *proto.Nil) (*proto.TokenSet, error) {
|
||||||
clitok, err := t.getAuth(ctx, "token:getall")
|
ctx, clitok, err := t.getAuth(ctx, "get all tokens", "token:getall")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, handleError(ctx, clitok, err, ln.F{"action": "Token.GetAll_getAuth"})
|
return nil, handleError(ctx, clitok, err, ln.F{"action": "Token.GetAll_getAuth"})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tr, _ := trace.FromContext(ctx)
|
||||||
|
defer tr.Finish()
|
||||||
|
|
||||||
toks, err := t.db.GetTokensForOwner(ctx, clitok.Owner)
|
toks, err := t.db.GetTokensForOwner(ctx, clitok.Owner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, handleError(ctx, clitok, err, ln.F{"action": "Token.GetAll_db.GetTokensForOwner"})
|
return nil, handleError(ctx, clitok, err, ln.F{"action": "Token.GetAll_db.GetTokensForOwner"})
|
||||||
|
@ -64,43 +71,58 @@ func (t *Token) GetAll(ctx context.Context, req *proto.Nil) (*proto.TokenSet, er
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Token) Put(ctx context.Context, tok *proto.Token) (*proto.Token, error) {
|
func (t *Token) Put(ctx context.Context, tok *proto.Token) (*proto.Token, error) {
|
||||||
clitok, err := t.getAuth(ctx, "token:put")
|
ctx, clitok, err := t.getAuth(ctx, "put new token", "token:put")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, handleError(ctx, clitok, err, ln.F{"action": "Token.Put_getAuth"})
|
return nil, handleError(ctx, clitok, err, ln.F{"action": "not authorized"})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tr, _ := trace.FromContext(ctx)
|
||||||
|
defer tr.Finish()
|
||||||
|
|
||||||
dbt, err := t.db.PutToken(ctx, uuid.New(), clitok.Owner, tok.Scopes)
|
dbt, err := t.db.PutToken(ctx, uuid.New(), clitok.Owner, tok.Scopes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, handleError(ctx, clitok, err, ln.F{"action": "Token.Put_db.PutToken"})
|
return nil, handleError(ctx, clitok, err, ln.F{"action": "put token into database", "scopes": tok.Scopes})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ln.Log(ctx, dbt, ln.Action("new token created"))
|
||||||
|
|
||||||
return dbt.AsProto(), nil
|
return dbt.AsProto(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Token) Delete(ctx context.Context, tok *proto.Token) (*proto.Nil, error) {
|
func (t *Token) Delete(ctx context.Context, tok *proto.Token) (*proto.Nil, error) {
|
||||||
clitok, err := t.getAuth(ctx, "token:delete")
|
ctx, clitok, err := t.getAuth(ctx, "delete single token", "token:delete")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, handleError(ctx, clitok, err, ln.F{"action": "Token.Delete_getAuth"})
|
return nil, handleError(ctx, clitok, err, ln.F{"action": "not authorized"})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tr, _ := trace.FromContext(ctx)
|
||||||
|
defer tr.Finish()
|
||||||
|
|
||||||
err = t.db.DeleteToken(ctx, tok.Id)
|
err = t.db.DeleteToken(ctx, tok.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, handleError(ctx, clitok, err, ln.F{"action": "Token.Delete_db.DeleteToken"})
|
return nil, handleError(ctx, clitok, err, ln.F{"action": "delete token from database", "token_id": tok.Id})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ln.Log(ctx, clitok, ln.Action("token deleted"), ln.F{"token_id": tok.Id})
|
||||||
|
|
||||||
return &proto.Nil{}, nil
|
return &proto.Nil{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Token) Deactivate(ctx context.Context, tok *proto.Token) (*proto.Nil, error) {
|
func (t *Token) Deactivate(ctx context.Context, tok *proto.Token) (*proto.Nil, error) {
|
||||||
clitok, err := t.getAuth(ctx, "token:deactivate")
|
ctx, clitok, err := t.getAuth(ctx, "deactivate single token", "token:deactivate")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, handleError(ctx, clitok, err, ln.F{"action": "Token.Deactivate_getAuth"})
|
return nil, handleError(ctx, clitok, err, ln.F{"action": "not authorized"})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tr, _ := trace.FromContext(ctx)
|
||||||
|
defer tr.Finish()
|
||||||
|
|
||||||
err = t.db.DeactivateToken(ctx, tok.Id)
|
err = t.db.DeactivateToken(ctx, tok.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, handleError(ctx, clitok, err, ln.F{"action": "Token.Deactivate_db.DeactivateToken"})
|
return nil, handleError(ctx, clitok, err, ln.F{"action": "deactivate token in database", "token_id": tok.Id})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ln.Log(ctx, clitok, ln.Action("deactivated token"), ln.F{"token_id": tok.Id})
|
||||||
|
|
||||||
return &proto.Nil{}, nil
|
return &proto.Nil{}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,14 +50,18 @@ func (c *Connection) F() ln.F {
|
||||||
// Ping ends a "ping" to the client. If the client doesn't respond or the connection
|
// Ping ends a "ping" to the client. If the client doesn't respond or the connection
|
||||||
// dies, then the connection needs to be cleaned up.
|
// dies, then the connection needs to be cleaned up.
|
||||||
func (c *Connection) Ping() error {
|
func (c *Connection) Ping() error {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
req, err := http.NewRequest("GET", "http://backend/health", nil)
|
req, err := http.NewRequest("GET", "http://backend/health", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
req = req.WithContext(ctx)
|
||||||
|
|
||||||
_, err = c.RoundTrip(req)
|
_, err = c.RoundTrip(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ln.Error(err, c.F(), ln.F{"action": "ping_roundtrip"})
|
ln.Error(ctx, err, c, ln.Action("pinging the backend"))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,20 +71,20 @@ func (c *Connection) Ping() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenStream creates a new stream (connection) to the backend server.
|
// OpenStream creates a new stream (connection) to the backend server.
|
||||||
func (c *Connection) OpenStream() (net.Conn, error) {
|
func (c *Connection) OpenStream(ctx context.Context) (net.Conn, error) {
|
||||||
if !c.usable {
|
if !c.usable {
|
||||||
return nil, ErrNoSuchBackend
|
return nil, ErrNoSuchBackend
|
||||||
}
|
}
|
||||||
|
|
||||||
err := c.conn.SetDeadline(time.Now().Add(time.Second))
|
err := c.conn.SetDeadline(time.Now().Add(time.Second))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ln.Error(err, c.F())
|
ln.Error(ctx, err, c)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
stream, err := c.session.OpenStream()
|
stream, err := c.session.OpenStream()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ln.Error(err, c.F())
|
ln.Error(ctx, err, c)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,7 +121,7 @@ var (
|
||||||
// RoundTrip forwards a HTTP request to the remote backend and then returns the
|
// RoundTrip forwards a HTTP request to the remote backend and then returns the
|
||||||
// response, if any.
|
// response, if any.
|
||||||
func (c *Connection) RoundTrip(req *http.Request) (*http.Response, error) {
|
func (c *Connection) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||||
stream, err := c.OpenStream()
|
stream, err := c.OpenStream(req.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, ErrCantOpenSessionStream.Error())
|
return nil, errors.Wrap(err, ErrCantOpenSessionStream.Error())
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,7 +146,10 @@ func (s *Server) GetAllBackends() []Backend {
|
||||||
// ListenAndServe starts the backend TCP/KCP listeners and relays backend
|
// ListenAndServe starts the backend TCP/KCP listeners and relays backend
|
||||||
// traffic to and from them.
|
// traffic to and from them.
|
||||||
func (s *Server) ListenAndServe() error {
|
func (s *Server) ListenAndServe() error {
|
||||||
ln.Log(ln.F{
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
ln.Log(ctx, ln.F{
|
||||||
"action": "listen_and_serve_called",
|
"action": "listen_and_serve_called",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -157,7 +160,7 @@ func (s *Server) ListenAndServe() error {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ln.Log(ln.F{
|
ln.Log(ctx, ln.F{
|
||||||
"action": "tcp+tls_listening",
|
"action": "tcp+tls_listening",
|
||||||
"addr": l.Addr(),
|
"addr": l.Addr(),
|
||||||
})
|
})
|
||||||
|
@ -165,11 +168,11 @@ func (s *Server) ListenAndServe() error {
|
||||||
for {
|
for {
|
||||||
conn, err := l.Accept()
|
conn, err := l.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ln.Error(err, ln.F{"kind": "tcp", "addr": l.Addr().String()})
|
ln.Error(ctx, err, ln.F{"kind": "tcp", "addr": l.Addr().String()})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
ln.Log(ln.F{
|
ln.Log(ctx, ln.F{
|
||||||
"action": "new_client",
|
"action": "new_client",
|
||||||
"kcp": false,
|
"kcp": false,
|
||||||
"addr": conn.RemoteAddr(),
|
"addr": conn.RemoteAddr(),
|
||||||
|
@ -187,7 +190,7 @@ func (s *Server) ListenAndServe() error {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ln.Log(ln.F{
|
ln.Log(ctx, ln.F{
|
||||||
"action": "kcp+tls_listening",
|
"action": "kcp+tls_listening",
|
||||||
"addr": l.Addr(),
|
"addr": l.Addr(),
|
||||||
})
|
})
|
||||||
|
@ -195,10 +198,10 @@ func (s *Server) ListenAndServe() error {
|
||||||
for {
|
for {
|
||||||
conn, err := l.Accept()
|
conn, err := l.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ln.Error(err, ln.F{"kind": "kcp", "addr": l.Addr().String()})
|
ln.Error(ctx, err, ln.F{"kind": "kcp", "addr": l.Addr().String()})
|
||||||
}
|
}
|
||||||
|
|
||||||
ln.Log(ln.F{
|
ln.Log(ctx, ln.F{
|
||||||
"action": "new_client",
|
"action": "new_client",
|
||||||
"kcp": true,
|
"kcp": true,
|
||||||
"addr": conn.RemoteAddr(),
|
"addr": conn.RemoteAddr(),
|
||||||
|
@ -223,7 +226,7 @@ func (s *Server) ListenAndServe() error {
|
||||||
failureChance := c.detector.Phi(now)
|
failureChance := c.detector.Phi(now)
|
||||||
|
|
||||||
if failureChance > 0.8 {
|
if failureChance > 0.8 {
|
||||||
ln.Log(c.F(), ln.F{
|
ln.Log(ctx, c.F(), ln.F{
|
||||||
"action": "phi_failure_detection",
|
"action": "phi_failure_detection",
|
||||||
"value": failureChance,
|
"value": failureChance,
|
||||||
})
|
})
|
||||||
|
@ -247,7 +250,7 @@ func (s *Server) HandleConn(c net.Conn, isKCP bool) {
|
||||||
|
|
||||||
session, err := smux.Server(c, s.cfg.SmuxConf)
|
session, err := smux.Server(c, s.cfg.SmuxConf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ln.Error(err, ln.F{
|
ln.Error(ctx, err, ln.F{
|
||||||
"action": "session_failure",
|
"action": "session_failure",
|
||||||
"local": c.LocalAddr().String(),
|
"local": c.LocalAddr().String(),
|
||||||
"remote": c.RemoteAddr().String(),
|
"remote": c.RemoteAddr().String(),
|
||||||
|
@ -261,7 +264,7 @@ func (s *Server) HandleConn(c net.Conn, isKCP bool) {
|
||||||
|
|
||||||
controlStream, err := session.OpenStream()
|
controlStream, err := session.OpenStream()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ln.Error(err, ln.F{
|
ln.Error(ctx, err, ln.F{
|
||||||
"action": "control_stream_failure",
|
"action": "control_stream_failure",
|
||||||
"local": c.LocalAddr().String(),
|
"local": c.LocalAddr().String(),
|
||||||
"remote": c.RemoteAddr().String(),
|
"remote": c.RemoteAddr().String(),
|
||||||
|
@ -275,7 +278,7 @@ func (s *Server) HandleConn(c net.Conn, isKCP bool) {
|
||||||
auth := &Auth{}
|
auth := &Auth{}
|
||||||
err = csd.Decode(auth)
|
err = csd.Decode(auth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ln.Error(err, ln.F{
|
ln.Error(ctx, err, ln.F{
|
||||||
"action": "control_stream_auth_decoding_failure",
|
"action": "control_stream_auth_decoding_failure",
|
||||||
"local": c.LocalAddr().String(),
|
"local": c.LocalAddr().String(),
|
||||||
"remote": c.RemoteAddr().String(),
|
"remote": c.RemoteAddr().String(),
|
||||||
|
@ -286,7 +289,7 @@ func (s *Server) HandleConn(c net.Conn, isKCP bool) {
|
||||||
|
|
||||||
routeUser, err := s.cfg.Storage.HasRoute(auth.Domain)
|
routeUser, err := s.cfg.Storage.HasRoute(auth.Domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ln.Error(err, ln.F{
|
ln.Error(ctx, err, ln.F{
|
||||||
"action": "nosuch_domain",
|
"action": "nosuch_domain",
|
||||||
"local": c.LocalAddr().String(),
|
"local": c.LocalAddr().String(),
|
||||||
"remote": c.RemoteAddr().String(),
|
"remote": c.RemoteAddr().String(),
|
||||||
|
@ -297,7 +300,7 @@ func (s *Server) HandleConn(c net.Conn, isKCP bool) {
|
||||||
|
|
||||||
tokenUser, scopes, err := s.cfg.Storage.HasToken(auth.Token)
|
tokenUser, scopes, err := s.cfg.Storage.HasToken(auth.Token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ln.Error(err, ln.F{
|
ln.Error(ctx, err, ln.F{
|
||||||
"action": "nosuch_token",
|
"action": "nosuch_token",
|
||||||
"local": c.LocalAddr().String(),
|
"local": c.LocalAddr().String(),
|
||||||
"remote": c.RemoteAddr().String(),
|
"remote": c.RemoteAddr().String(),
|
||||||
|
@ -315,7 +318,7 @@ func (s *Server) HandleConn(c net.Conn, isKCP bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
ln.Error(ErrAuthMismatch, ln.F{
|
ln.Error(ctx, ErrAuthMismatch, ln.F{
|
||||||
"action": "token_not_authorized",
|
"action": "token_not_authorized",
|
||||||
"local": c.LocalAddr().String(),
|
"local": c.LocalAddr().String(),
|
||||||
"remote": c.RemoteAddr().String(),
|
"remote": c.RemoteAddr().String(),
|
||||||
|
@ -323,7 +326,7 @@ func (s *Server) HandleConn(c net.Conn, isKCP bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if routeUser != tokenUser {
|
if routeUser != tokenUser {
|
||||||
ln.Error(ErrAuthMismatch, ln.F{
|
ln.Error(ctx, ErrAuthMismatch, ln.F{
|
||||||
"action": "auth_mismatch",
|
"action": "auth_mismatch",
|
||||||
"local": c.LocalAddr().String(),
|
"local": c.LocalAddr().String(),
|
||||||
"remote": c.RemoteAddr().String(),
|
"remote": c.RemoteAddr().String(),
|
||||||
|
@ -346,11 +349,11 @@ func (s *Server) HandleConn(c net.Conn, isKCP bool) {
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
ln.Log(connection, ln.F{"action": "connection handler panic", "err": r})
|
ln.Log(ctx, connection, ln.F{"action": "connection handler panic", "err": r})
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
ln.Log(ln.F{
|
ln.Log(ctx, ln.F{
|
||||||
"action": "backend_connected",
|
"action": "backend_connected",
|
||||||
}, connection.F())
|
}, connection.F())
|
||||||
|
|
||||||
|
@ -386,7 +389,7 @@ func (s *Server) HandleConn(c net.Conn, isKCP bool) {
|
||||||
connection.cancel()
|
connection.cancel()
|
||||||
}
|
}
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
s.RemoveConn(connection)
|
s.RemoveConn(ctx, connection)
|
||||||
connection.Close()
|
connection.Close()
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -395,7 +398,7 @@ func (s *Server) HandleConn(c net.Conn, isKCP bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveConn removes a connection.
|
// RemoveConn removes a connection.
|
||||||
func (s *Server) RemoveConn(connection *Connection) {
|
func (s *Server) RemoveConn(ctx context.Context, connection *Connection) {
|
||||||
s.connlock.Lock()
|
s.connlock.Lock()
|
||||||
delete(s.conns, connection.conn)
|
delete(s.conns, connection.conn)
|
||||||
s.connlock.Unlock()
|
s.connlock.Unlock()
|
||||||
|
@ -408,7 +411,7 @@ func (s *Server) RemoveConn(connection *Connection) {
|
||||||
if ok {
|
if ok {
|
||||||
conns, ok = val.([]*Connection)
|
conns, ok = val.([]*Connection)
|
||||||
if !ok {
|
if !ok {
|
||||||
ln.Error(ErrCantRemoveWhatDoesntExist, connection.F(), ln.F{
|
ln.Error(ctx, ErrCantRemoveWhatDoesntExist, connection.F(), ln.F{
|
||||||
"action": "looking_up_for_disconnect_removal",
|
"action": "looking_up_for_disconnect_removal",
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
|
@ -428,7 +431,7 @@ func (s *Server) RemoveConn(connection *Connection) {
|
||||||
s.domains.Remove(auth.Domain)
|
s.domains.Remove(auth.Domain)
|
||||||
}
|
}
|
||||||
|
|
||||||
ln.Log(connection.F(), ln.F{
|
ln.Log(ctx, connection.F(), ln.F{
|
||||||
"action": "client_disconnecting",
|
"action": "client_disconnecting",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -469,12 +472,13 @@ func gen502Page(req *http.Request) *http.Response {
|
||||||
// RoundTrip sends a HTTP request to a backend and then returns its response.
|
// RoundTrip sends a HTTP request to a backend and then returns its response.
|
||||||
func (s *Server) RoundTrip(req *http.Request) (*http.Response, error) {
|
func (s *Server) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||||
var conns []*Connection
|
var conns []*Connection
|
||||||
|
ctx := req.Context()
|
||||||
|
|
||||||
val, ok := s.domains.Get(req.Host)
|
val, ok := s.domains.Get(req.Host)
|
||||||
if ok {
|
if ok {
|
||||||
conns, ok = val.([]*Connection)
|
conns, ok = val.([]*Connection)
|
||||||
if !ok {
|
if !ok {
|
||||||
ln.Error(ErrNoSuchBackend, ln.F{
|
ln.Error(ctx, ErrNoSuchBackend, ln.F{
|
||||||
"action": "no_backend_connected",
|
"action": "no_backend_connected",
|
||||||
"remote": req.RemoteAddr,
|
"remote": req.RemoteAddr,
|
||||||
"host": req.Host,
|
"host": req.Host,
|
||||||
|
@ -493,7 +497,7 @@ func (s *Server) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(goodConns) == 0 {
|
if len(goodConns) == 0 {
|
||||||
ln.Error(ErrNoSuchBackend, ln.F{
|
ln.Error(ctx, ErrNoSuchBackend, ln.F{
|
||||||
"action": "no_backend_connected",
|
"action": "no_backend_connected",
|
||||||
"remote": req.RemoteAddr,
|
"remote": req.RemoteAddr,
|
||||||
"host": req.Host,
|
"host": req.Host,
|
||||||
|
@ -507,7 +511,7 @@ func (s *Server) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||||
|
|
||||||
resp, err := c.RoundTrip(req)
|
resp, err := c.RoundTrip(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ln.Error(err, c.F(), ln.F{
|
ln.Error(ctx, err, c, ln.F{
|
||||||
"action": "connection_roundtrip",
|
"action": "connection_roundtrip",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -515,7 +519,7 @@ func (s *Server) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ln.Log(c.F(), ln.F{
|
ln.Log(ctx, c, ln.F{
|
||||||
"action": "http_traffic",
|
"action": "http_traffic",
|
||||||
"remote_addr": req.RemoteAddr,
|
"remote_addr": req.RemoteAddr,
|
||||||
"host": req.Host,
|
"host": req.Host,
|
||||||
|
|
|
@ -323,3 +323,10 @@ b6e1ae21643682ce023deb8d152024597b0e9bb4 golang.org/x/sys/unix
|
||||||
8443e311d3925f5e20494496790670942ed48504 google.golang.org/grpc/status
|
8443e311d3925f5e20494496790670942ed48504 google.golang.org/grpc/status
|
||||||
8443e311d3925f5e20494496790670942ed48504 google.golang.org/grpc/tap
|
8443e311d3925f5e20494496790670942ed48504 google.golang.org/grpc/tap
|
||||||
8443e311d3925f5e20494496790670942ed48504 google.golang.org/grpc/transport
|
8443e311d3925f5e20494496790670942ed48504 google.golang.org/grpc/transport
|
||||||
|
466e05b2ef3e48ce08a367b6aaac09ee29a124e5 github.com/Xe/ln
|
||||||
|
2b3a18b5f0fb6b4f9190549597d3f962c02bc5eb github.com/pkg/errors
|
||||||
|
466e05b2ef3e48ce08a367b6aaac09ee29a124e5 github.com/Xe/ln
|
||||||
|
466e05b2ef3e48ce08a367b6aaac09ee29a124e5 github.com/Xe/ln/ex
|
||||||
|
2b3a18b5f0fb6b4f9190549597d3f962c02bc5eb github.com/pkg/errors
|
||||||
|
0a9397675ba34b2845f758fe3cd68828369c6517 golang.org/x/net/internal/timeseries
|
||||||
|
0a9397675ba34b2845f758fe3cd68828369c6517 golang.org/x/net/trace
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
package ln
|
||||||
|
|
||||||
|
// Action is a convenience helper for logging the "action" being performed as
|
||||||
|
// part of a log line.
|
||||||
|
//
|
||||||
|
// It is a convenience wrapper for the following:
|
||||||
|
//
|
||||||
|
// ln.Log(ctx, fer, f, ln.Action("writing frozberry sales reports to database"))
|
||||||
|
func Action(act string) Fer {
|
||||||
|
return F{"action": act}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
package ln
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ctxKey int
|
||||||
|
|
||||||
|
const (
|
||||||
|
fKey = iota
|
||||||
|
)
|
||||||
|
|
||||||
|
// WithF stores or appends a given F instance into a context.
|
||||||
|
func WithF(ctx context.Context, f F) context.Context {
|
||||||
|
pf, ok := FFromContext(ctx)
|
||||||
|
if !ok {
|
||||||
|
return context.WithValue(ctx, fKey, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
pf.Extend(f)
|
||||||
|
|
||||||
|
return context.WithValue(ctx, fKey, pf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FFromContext fetches the `F` out of the context if it exists.
|
||||||
|
func FFromContext(ctx context.Context) (F, bool) {
|
||||||
|
fvp := ctx.Value(fKey)
|
||||||
|
if fvp == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
f, ok := fvp.(F)
|
||||||
|
if !ok {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return f, true
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
/*
|
||||||
|
Package ex is a set of extensions and middleware for ln.
|
||||||
|
|
||||||
|
This package will (inevitably) have a lot of third-party dependencies and
|
||||||
|
as such might be broken apart into other packages in the future.
|
||||||
|
*/
|
||||||
|
package ex
|
|
@ -0,0 +1,68 @@
|
||||||
|
package ex
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/Xe/ln"
|
||||||
|
"golang.org/x/net/trace"
|
||||||
|
)
|
||||||
|
|
||||||
|
type goEventLogger struct {
|
||||||
|
ev trace.EventLog
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGoEventLogger will log ln information to a given trace.EventLog instance.
|
||||||
|
func NewGoEventLogger(ev trace.EventLog) ln.Filter {
|
||||||
|
return &goEventLogger{ev: ev}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gel *goEventLogger) Apply(ctx context.Context, e ln.Event) bool {
|
||||||
|
data, err := ln.DefaultFormatter.Format(ctx, e)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("wtf: error in log formatting: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if everr := e.Data["err"]; everr != nil {
|
||||||
|
gel.ev.Errorf("%s", string(data))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
gel.ev.Printf("%s", string(data))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gel *goEventLogger) Close() { gel.ev.Finish() }
|
||||||
|
func (gel *goEventLogger) Run() {}
|
||||||
|
|
||||||
|
type sst string
|
||||||
|
|
||||||
|
func (s sst) String() string { return string(s) }
|
||||||
|
|
||||||
|
func goTraceLogger(ctx context.Context, e ln.Event) bool {
|
||||||
|
sp, ok := trace.FromContext(ctx)
|
||||||
|
if !ok {
|
||||||
|
return true // no trace in context
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := ln.DefaultFormatter.Format(ctx, e)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("wtf: error in log formatting: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if everr := e.Data["err"]; everr != nil {
|
||||||
|
sp.SetError()
|
||||||
|
}
|
||||||
|
|
||||||
|
sp.LazyLog(sst(string(data)), false)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGoTraceLogger will log ln information to a golang.org/x/net/trace.Trace
|
||||||
|
// if it is present in the context of ln calls.
|
||||||
|
func NewGoTraceLogger() ln.Filter {
|
||||||
|
return ln.FilterFunc(goTraceLogger)
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package ex
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Xe/ln"
|
||||||
|
)
|
||||||
|
|
||||||
|
func HTTPLog(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
host, _, _ := net.SplitHostPort(r.RemoteAddr)
|
||||||
|
f := ln.F{
|
||||||
|
"remote_ip": host,
|
||||||
|
"x_forwarded_for": r.Header.Get("X-Forwarded-For"),
|
||||||
|
"path": r.URL.Path,
|
||||||
|
}
|
||||||
|
ctx := ln.WithF(r.Context(), f)
|
||||||
|
st := time.Now()
|
||||||
|
|
||||||
|
next.ServeHTTP(w, r.WithContext(ctx))
|
||||||
|
|
||||||
|
af := time.Now()
|
||||||
|
f["request_duration"] = af.Sub(st)
|
||||||
|
|
||||||
|
ws, ok := w.(interface {
|
||||||
|
Status() int
|
||||||
|
})
|
||||||
|
if ok {
|
||||||
|
f["status"] = ws.Status()
|
||||||
|
}
|
||||||
|
|
||||||
|
ln.Log(r.Context(), f)
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package ex
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Xe/ln"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This file deals with formatting of [l2met] style metrics.
|
||||||
|
// [l2met]: https://r.32k.io/l2met-introduction
|
||||||
|
|
||||||
|
// Counter formats a value as a metrics counter.
|
||||||
|
func Counter(name string, value int) ln.Fer {
|
||||||
|
return ln.F{"count#" + name: value}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gauge formats a value as a metrics gauge.
|
||||||
|
func Gauge(name string, value int) ln.Fer {
|
||||||
|
return ln.F{"gauge#" + name: value}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Measure formats a value as a metrics measure.
|
||||||
|
func Measure(name string, ts time.Time) ln.Fer {
|
||||||
|
return ln.F{"measure#" + name: time.Since(ts)}
|
||||||
|
}
|
|
@ -1,23 +1,24 @@
|
||||||
package ln
|
package ln
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Filter interface for defining chain filters
|
// Filter interface for defining chain filters
|
||||||
type Filter interface {
|
type Filter interface {
|
||||||
Apply(Event) bool
|
Apply(ctx context.Context, e Event) bool
|
||||||
Run()
|
Run()
|
||||||
Close()
|
Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// FilterFunc allows simple functions to implement the Filter interface
|
// FilterFunc allows simple functions to implement the Filter interface
|
||||||
type FilterFunc func(e Event) bool
|
type FilterFunc func(ctx context.Context, e Event) bool
|
||||||
|
|
||||||
// Apply implements the Filter interface
|
// Apply implements the Filter interface
|
||||||
func (ff FilterFunc) Apply(e Event) bool {
|
func (ff FilterFunc) Apply(ctx context.Context, e Event) bool {
|
||||||
return ff(e)
|
return ff(ctx, e)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run implements the Filter interface
|
// Run implements the Filter interface
|
||||||
|
@ -45,8 +46,8 @@ func NewWriterFilter(out io.Writer, format Formatter) *WriterFilter {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply implements the Filter interface
|
// Apply implements the Filter interface
|
||||||
func (w *WriterFilter) Apply(e Event) bool {
|
func (w *WriterFilter) Apply(ctx context.Context, e Event) bool {
|
||||||
output, err := w.Formatter.Format(e)
|
output, err := w.Formatter.Format(ctx, e)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
w.Lock()
|
w.Lock()
|
||||||
w.Out.Write(output)
|
w.Out.Write(output)
|
||||||
|
@ -63,4 +64,4 @@ func (w *WriterFilter) Run() {}
|
||||||
func (w *WriterFilter) Close() {}
|
func (w *WriterFilter) Close() {}
|
||||||
|
|
||||||
// NilFilter is safe to return as a Filter, but does nothing
|
// NilFilter is safe to return as a Filter, but does nothing
|
||||||
var NilFilter = FilterFunc(func(e Event) bool { return true })
|
var NilFilter = FilterFunc(func(_ context.Context, e Event) bool { return true })
|
||||||
|
|
|
@ -2,6 +2,7 @@ package ln
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -13,7 +14,7 @@ var (
|
||||||
|
|
||||||
// Formatter defines the formatting of events
|
// Formatter defines the formatting of events
|
||||||
type Formatter interface {
|
type Formatter interface {
|
||||||
Format(Event) ([]byte, error)
|
Format(ctx context.Context, e Event) ([]byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultFormatter is the default way in which to format events
|
// DefaultFormatter is the default way in which to format events
|
||||||
|
@ -36,7 +37,7 @@ func NewTextFormatter() Formatter {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format implements the Formatter interface
|
// Format implements the Formatter interface
|
||||||
func (t *TextFormatter) Format(e Event) ([]byte, error) {
|
func (t *TextFormatter) Format(_ context.Context, e Event) ([]byte, error) {
|
||||||
var writer bytes.Buffer
|
var writer bytes.Buffer
|
||||||
|
|
||||||
writer.WriteString("time=\"")
|
writer.WriteString("time=\"")
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package ln
|
package ln
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -61,7 +62,7 @@ type Event struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log is the generic logging method.
|
// Log is the generic logging method.
|
||||||
func (l *Logger) Log(xs ...Fer) {
|
func (l *Logger) Log(ctx context.Context, xs ...Fer) {
|
||||||
event := Event{Time: time.Now()}
|
event := Event{Time: time.Now()}
|
||||||
|
|
||||||
addF := func(bf F) {
|
addF := func(bf F) {
|
||||||
|
@ -78,6 +79,11 @@ func (l *Logger) Log(xs ...Fer) {
|
||||||
addF(f.F())
|
addF(f.F())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctxf, ok := FFromContext(ctx)
|
||||||
|
if ok {
|
||||||
|
addF(ctxf)
|
||||||
|
}
|
||||||
|
|
||||||
if os.Getenv("LN_DEBUG_ALL_EVENTS") == "1" {
|
if os.Getenv("LN_DEBUG_ALL_EVENTS") == "1" {
|
||||||
frame := callersFrame()
|
frame := callersFrame()
|
||||||
if event.Data == nil {
|
if event.Data == nil {
|
||||||
|
@ -88,19 +94,19 @@ func (l *Logger) Log(xs ...Fer) {
|
||||||
event.Data["_filename"] = frame.filename
|
event.Data["_filename"] = frame.filename
|
||||||
}
|
}
|
||||||
|
|
||||||
l.filter(event)
|
l.filter(ctx, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Logger) filter(e Event) {
|
func (l *Logger) filter(ctx context.Context, e Event) {
|
||||||
for _, f := range l.Filters {
|
for _, f := range l.Filters {
|
||||||
if !f.Apply(e) {
|
if !f.Apply(ctx, e) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error logs an error and information about the context of said error.
|
// Error logs an error and information about the context of said error.
|
||||||
func (l *Logger) Error(err error, xs ...Fer) {
|
func (l *Logger) Error(ctx context.Context, err error, xs ...Fer) {
|
||||||
data := F{}
|
data := F{}
|
||||||
frame := callersFrame()
|
frame := callersFrame()
|
||||||
|
|
||||||
|
@ -116,20 +122,20 @@ func (l *Logger) Error(err error, xs ...Fer) {
|
||||||
|
|
||||||
xs = append(xs, data)
|
xs = append(xs, data)
|
||||||
|
|
||||||
l.Log(xs...)
|
l.Log(ctx, xs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fatal logs this set of values, then exits with status code 1.
|
// Fatal logs this set of values, then exits with status code 1.
|
||||||
func (l *Logger) Fatal(xs ...Fer) {
|
func (l *Logger) Fatal(ctx context.Context, xs ...Fer) {
|
||||||
xs = append(xs, F{"fatal": true})
|
xs = append(xs, F{"fatal": true})
|
||||||
|
|
||||||
l.Log(xs...)
|
l.Log(ctx, xs...)
|
||||||
|
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FatalErr combines Fatal and Error.
|
// FatalErr combines Fatal and Error.
|
||||||
func (l *Logger) FatalErr(err error, xs ...Fer) {
|
func (l *Logger) FatalErr(ctx context.Context, err error, xs ...Fer) {
|
||||||
xs = append(xs, F{"fatal": true})
|
xs = append(xs, F{"fatal": true})
|
||||||
|
|
||||||
data := F{}
|
data := F{}
|
||||||
|
@ -146,7 +152,7 @@ func (l *Logger) FatalErr(err error, xs ...Fer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
xs = append(xs, data)
|
xs = append(xs, data)
|
||||||
l.Log(xs...)
|
l.Log(ctx, xs...)
|
||||||
|
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
@ -154,21 +160,21 @@ func (l *Logger) FatalErr(err error, xs ...Fer) {
|
||||||
// Default Implementation
|
// Default Implementation
|
||||||
|
|
||||||
// Log is the generic logging method.
|
// Log is the generic logging method.
|
||||||
func Log(xs ...Fer) {
|
func Log(ctx context.Context, xs ...Fer) {
|
||||||
DefaultLogger.Log(xs...)
|
DefaultLogger.Log(ctx, xs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error logs an error and information about the context of said error.
|
// Error logs an error and information about the context of said error.
|
||||||
func Error(err error, xs ...Fer) {
|
func Error(ctx context.Context, err error, xs ...Fer) {
|
||||||
DefaultLogger.Error(err, xs...)
|
DefaultLogger.Error(ctx, err, xs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fatal logs this set of values, then exits with status code 1.
|
// Fatal logs this set of values, then exits with status code 1.
|
||||||
func Fatal(xs ...Fer) {
|
func Fatal(ctx context.Context, xs ...Fer) {
|
||||||
DefaultLogger.Fatal(xs...)
|
DefaultLogger.Fatal(ctx, xs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FatalErr combines Fatal and Error.
|
// FatalErr combines Fatal and Error.
|
||||||
func FatalErr(err error, xs ...Fer) {
|
func FatalErr(ctx context.Context, err error, xs ...Fer) {
|
||||||
DefaultLogger.FatalErr(err, xs...)
|
DefaultLogger.FatalErr(ctx, err, xs...)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue