Runtime logs (#1447)
* Runtime logs * Slightly broken * Pushing for diff * Log trailing works locally * LogsOptions * Comments and streamcount support for local logs * Adding kubernetes logs * Fixing k8s logs * K8s fixes * StreamCount is now nuked * PR comments * PR comments again * Fix typo
This commit is contained in:
		| @@ -2,9 +2,16 @@ package runtime | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/hpcloud/tail" | ||||
| 	"github.com/micro/go-micro/v2/logger" | ||||
| ) | ||||
|  | ||||
| @@ -169,6 +176,11 @@ func (r *runtime) run(events <-chan Event) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func logFile(serviceName string) string { | ||||
| 	name := strings.Replace(serviceName, "/", "-", -1) | ||||
| 	return filepath.Join(os.TempDir(), fmt.Sprintf("%v.log", name)) | ||||
| } | ||||
|  | ||||
| // Create creates a new service which is then started by runtime | ||||
| func (r *runtime) Create(s *Service, opts ...CreateOption) error { | ||||
| 	r.Lock() | ||||
| @@ -191,6 +203,17 @@ func (r *runtime) Create(s *Service, opts ...CreateOption) error { | ||||
| 	// create new service | ||||
| 	service := newService(s, options) | ||||
|  | ||||
| 	f, err := os.OpenFile(logFile(service.Name), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) | ||||
| 	logger.Info(f, err) | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	if service.output != nil { | ||||
| 		service.output = io.MultiWriter(service.output, f) | ||||
| 	} else { | ||||
| 		service.output = f | ||||
| 	} | ||||
| 	// start the service | ||||
| 	if err := service.Start(); err != nil { | ||||
| 		return err | ||||
| @@ -202,6 +225,62 @@ func (r *runtime) Create(s *Service, opts ...CreateOption) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // @todo: Getting existing lines is not supported yet. | ||||
| // The reason for this is because it's hard to calculate line offset | ||||
| // as opposed to character offset. | ||||
| // This logger streams by default and only supports the `StreamCount` option. | ||||
| func (r *runtime) Logs(s *Service, options ...LogsOption) (LogStream, error) { | ||||
| 	lopts := LogsOptions{} | ||||
| 	for _, o := range options { | ||||
| 		o(&lopts) | ||||
| 	} | ||||
| 	ret := &logStream{ | ||||
| 		service: s.Name, | ||||
| 		stream:  make(chan LogRecord), | ||||
| 		stop:    make(chan bool), | ||||
| 	} | ||||
| 	t, err := tail.TailFile(logFile(s.Name), tail.Config{Follow: true, Location: &tail.SeekInfo{ | ||||
| 		Whence: 2, | ||||
| 		Offset: 0, | ||||
| 	}, Logger: tail.DiscardingLogger}) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	ret.tail = t | ||||
| 	go func() { | ||||
| 		for line := range t.Lines { | ||||
| 			ret.stream <- LogRecord{Message: line.Text} | ||||
| 		} | ||||
| 	}() | ||||
| 	return ret, nil | ||||
| } | ||||
|  | ||||
| type logStream struct { | ||||
| 	tail    *tail.Tail | ||||
| 	service string | ||||
| 	stream  chan LogRecord | ||||
| 	stop    chan bool | ||||
| } | ||||
|  | ||||
| func (l *logStream) Chan() chan LogRecord { | ||||
| 	return l.stream | ||||
| } | ||||
|  | ||||
| func (l *logStream) Stop() error { | ||||
| 	// @todo seems like this is causing a hangup | ||||
| 	//err := l.tail.Stop() | ||||
| 	//if err != nil { | ||||
| 	//	return err | ||||
| 	//} | ||||
| 	select { | ||||
| 	case <-l.stop: | ||||
| 		return nil | ||||
| 	default: | ||||
| 		close(l.stop) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Read returns all instances of requested service | ||||
| // If no service name is provided we return all the track services. | ||||
| func (r *runtime) Read(opts ...ReadOption) ([]*Service, error) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user