Merge branch 'Xe/fix/update-ln' of xena/route into master

This commit is contained in:
Cadey Ratio 2017-10-01 11:11:48 -04:00 committed by Gogs
commit 334f483574
24 changed files with 538 additions and 128 deletions

View File

@ -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})
} }

View File

@ -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)
} }
} }

View File

@ -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("", "")
}
} }

View File

@ -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:

View File

@ -1,4 +1,4 @@
package main package internal
import ( import (
"log" "log"

11
internal/init.go Normal file
View File

@ -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())
}

27
internal/manhole.go Normal file
View File

@ -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)
}

View File

@ -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)
})
}

View File

@ -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
} }

View File

@ -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
} }

View File

@ -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
} }

View File

@ -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
} }

View File

@ -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())
} }

View File

@ -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,

View File

@ -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

11
vendor/github.com/Xe/ln/action.go generated vendored Normal file
View File

@ -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}
}

38
vendor/github.com/Xe/ln/context.go generated vendored Normal file
View File

@ -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
}

7
vendor/github.com/Xe/ln/ex/doc.go generated vendored Normal file
View File

@ -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

68
vendor/github.com/Xe/ln/ex/gotrace.go generated vendored Normal file
View File

@ -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)
}

36
vendor/github.com/Xe/ln/ex/http.go generated vendored Normal file
View File

@ -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)
})
}

25
vendor/github.com/Xe/ln/ex/l2met.go generated vendored Normal file
View File

@ -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)}
}

15
vendor/github.com/Xe/ln/filter.go generated vendored
View File

@ -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 })

View File

@ -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=\"")

42
vendor/github.com/Xe/ln/logger.go generated vendored
View File

@ -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...)
} }