add logging service for service-wide logging
This commit is contained in:
		
							parent
							
								
									5fa4371b33
								
							
						
					
					
						commit
						0508a4867e
					
				|  | @ -0,0 +1,74 @@ | ||||||
|  | package main | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"encoding/json" | ||||||
|  | 	"fmt" | ||||||
|  | 	"os" | ||||||
|  | 	"strconv" | ||||||
|  | 	"strings" | ||||||
|  | 	"time" | ||||||
|  | 
 | ||||||
|  | 	"github.com/bdlm/log" | ||||||
|  | 	"github.com/satori/go.uuid" | ||||||
|  | 	"github.com/streadway/amqp" | ||||||
|  | 
 | ||||||
|  | 	srv "dev.sum7.eu/genofire/microservices-collection/logging" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | const ServiceName = "eu.sum7.log-cmd" | ||||||
|  | 
 | ||||||
|  | var ServiceID = uuid.Must(uuid.NewV4()) | ||||||
|  | 
 | ||||||
|  | func main() { | ||||||
|  | 	log.SetFormatter(&log.TextFormatter{ | ||||||
|  | 		DisableTimestamp: true, | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
|  | 	logLevel, err := strconv.ParseUint(os.Args[1], 10, 32) | ||||||
|  | 	if err != nil { | ||||||
|  | 		log.Fatalf("Failed to parse LogLevel: %s", err) | ||||||
|  | 	} | ||||||
|  | 	logMessage := srv.LogMessage{ | ||||||
|  | 		ServiceName: ServiceName, | ||||||
|  | 		ServiceID:   ServiceID, | ||||||
|  | 		Time:        time.Now(), | ||||||
|  | 		Level:       uint32(logLevel), | ||||||
|  | 		Message:     strings.Join(os.Args[2:], " "), | ||||||
|  | 	} | ||||||
|  | 	body, err := json.Marshal(logMessage) | ||||||
|  | 	if err != nil { | ||||||
|  | 		log.Fatalf("Failed to parse LogLevel: %s", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/") | ||||||
|  | 	if err != nil { | ||||||
|  | 		log.Fatalf("Failed to connect to RabbitMQ: %s", err) | ||||||
|  | 	} | ||||||
|  | 	defer conn.Close() | ||||||
|  | 
 | ||||||
|  | 	ch, err := conn.Channel() | ||||||
|  | 	if err != nil { | ||||||
|  | 		log.Fatalf("Failed to open a channel: %s", err) | ||||||
|  | 	} | ||||||
|  | 	defer ch.Close() | ||||||
|  | 
 | ||||||
|  | 	if err = srv.ExchangeDeclare(ch); err != nil { | ||||||
|  | 		log.Fatalf("Failed to declare an exchange: %s", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	err = ch.Publish( | ||||||
|  | 		srv.EXCHANGE, | ||||||
|  | 		fmt.Sprintf("%d.%s", logLevel, ServiceName), | ||||||
|  | 		false, | ||||||
|  | 		false, | ||||||
|  | 		amqp.Publishing{ | ||||||
|  | 			ContentType:  "application/json", | ||||||
|  | 			DeliveryMode: amqp.Persistent, | ||||||
|  | 			Body:         body, | ||||||
|  | 		}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		log.Fatalf("Failed to publish log message: %s", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	log.Printf(" [x] Sent %s", body) | ||||||
|  | } | ||||||
|  | @ -0,0 +1,128 @@ | ||||||
|  | package main | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"encoding/json" | ||||||
|  | 	"flag" | ||||||
|  | 	"fmt" | ||||||
|  | 	"os" | ||||||
|  | 	"os/signal" | ||||||
|  | 	"syscall" | ||||||
|  | 
 | ||||||
|  | 	"github.com/bdlm/log" | ||||||
|  | 	"github.com/bdlm/std/logger" | ||||||
|  | 	"github.com/streadway/amqp" | ||||||
|  | 
 | ||||||
|  | 	"dev.sum7.eu/genofire/microservices-collection/lib" | ||||||
|  | 	srv "dev.sum7.eu/genofire/microservices-collection/logging" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var logRecieved = false | ||||||
|  | 
 | ||||||
|  | func main() { | ||||||
|  | 	flag.BoolVar(&logRecieved, "recieved", logRecieved, "show recieved log on console") | ||||||
|  | 	flag.Parse() | ||||||
|  | 	lib.LogUpdateConfig() | ||||||
|  | 
 | ||||||
|  | 	conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/") | ||||||
|  | 	if err != nil { | ||||||
|  | 		log.Fatalf("Failed to connect to RabbitMQ: %s", err) | ||||||
|  | 	} | ||||||
|  | 	defer conn.Close() | ||||||
|  | 
 | ||||||
|  | 	ch, err := conn.Channel() | ||||||
|  | 	if err != nil { | ||||||
|  | 		log.Fatalf("Failed to open a channel: %s", err) | ||||||
|  | 	} | ||||||
|  | 	defer ch.Close() | ||||||
|  | 
 | ||||||
|  | 	if err = srv.ExchangeDeclare(ch); err != nil { | ||||||
|  | 		log.Fatalf("Failed to declare an exchange: %s", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	q, err := ch.QueueDeclare( | ||||||
|  | 		"",    // name
 | ||||||
|  | 		false, // durable
 | ||||||
|  | 		false, // delete when usused
 | ||||||
|  | 		true,  // exclusive
 | ||||||
|  | 		false, // no-wait
 | ||||||
|  | 		nil,   // arguments
 | ||||||
|  | 	) | ||||||
|  | 	if err != nil { | ||||||
|  | 		log.Fatalf("Failed to declare a queue: %s", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	err = ch.QueueBind( | ||||||
|  | 		q.Name,       // queue name
 | ||||||
|  | 		"",           // routing key
 | ||||||
|  | 		srv.EXCHANGE, // exchange
 | ||||||
|  | 		false, | ||||||
|  | 		nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		log.Fatalf("Failed to bind a queue: %s", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	msgs, err := ch.Consume( | ||||||
|  | 		q.Name, // queue
 | ||||||
|  | 		"",     // consumer
 | ||||||
|  | 		true,   // auto-ack
 | ||||||
|  | 		false,  // exclusive
 | ||||||
|  | 		false,  // no-local
 | ||||||
|  | 		false,  // no-wait
 | ||||||
|  | 		nil,    // args
 | ||||||
|  | 	) | ||||||
|  | 	if err != nil { | ||||||
|  | 		log.Fatalf("Failed to register a consumer: %s", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	loggerRecieved := log.New() | ||||||
|  | 	loggerRecieved.SetLevel(logger.Trace) | ||||||
|  | 
 | ||||||
|  | 	go func() { | ||||||
|  | 		for d := range msgs { | ||||||
|  | 			var logMessage *srv.LogMessage | ||||||
|  | 			if err := json.Unmarshal([]byte(d.Body), &logMessage); err != nil { | ||||||
|  | 				log.Fatal(err) | ||||||
|  | 			} | ||||||
|  | 			//TODO write to Database (to get last values for web client)
 | ||||||
|  | 
 | ||||||
|  | 			// output to console
 | ||||||
|  | 			if !logRecieved { | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			e := &log.Entry{ | ||||||
|  | 				Logger: loggerRecieved, | ||||||
|  | 				Time:   logMessage.Time, | ||||||
|  | 				Data:   logMessage.Data, | ||||||
|  | 			} | ||||||
|  | 			e = e.WithFields(map[string]interface{}{ | ||||||
|  | 				"service_name": logMessage.ServiceName, | ||||||
|  | 				"service_id":   logMessage.ServiceID, | ||||||
|  | 				"log_level":    logMessage.Level, | ||||||
|  | 			}) | ||||||
|  | 			lvl := logger.Level(uint32(logMessage.Level)) | ||||||
|  | 			if lvl >= logger.Trace { | ||||||
|  | 				e.Debug(fmt.Sprintf("[trace] %s", logMessage.Message)) | ||||||
|  | 			} else if lvl >= logger.Debug { | ||||||
|  | 				e.Debug(logMessage.Message) | ||||||
|  | 			} else if lvl >= logger.Info { | ||||||
|  | 				e.Info(logMessage.Message) | ||||||
|  | 			} else if lvl >= logger.Warn { | ||||||
|  | 				e.Warn(logMessage.Message) | ||||||
|  | 			} else if lvl >= logger.Error { | ||||||
|  | 				e.Error(logMessage.Message) | ||||||
|  | 			} else if lvl >= logger.Panic { | ||||||
|  | 				e.Error(fmt.Sprintf("[panic] %s", logMessage.Message)) | ||||||
|  | 			} else if lvl >= logger.Fatal { | ||||||
|  | 				e.Error(fmt.Sprintf("[fatal] %s", logMessage.Message)) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	}() | ||||||
|  | 
 | ||||||
|  | 	log.Debug("started") | ||||||
|  | 
 | ||||||
|  | 	// Wait for INT/TERM
 | ||||||
|  | 	sigs := make(chan os.Signal, 1) | ||||||
|  | 	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) | ||||||
|  | 	sig := <-sigs | ||||||
|  | 	log.WithField("recieved", sig).Info("stopped") | ||||||
|  | } | ||||||
|  | @ -0,0 +1,43 @@ | ||||||
|  | package logging | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"time" | ||||||
|  | 
 | ||||||
|  | 	"github.com/bdlm/log" | ||||||
|  | 	"github.com/satori/go.uuid" | ||||||
|  | 	"github.com/streadway/amqp" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | const EXCHANGE = "sum7.logging" | ||||||
|  | 
 | ||||||
|  | func ExchangeDeclare(ch *amqp.Channel) error { | ||||||
|  | 	return ch.ExchangeDeclare( | ||||||
|  | 		EXCHANGE, | ||||||
|  | 		"direct", | ||||||
|  | 		true, | ||||||
|  | 		false, | ||||||
|  | 		false, | ||||||
|  | 		false, | ||||||
|  | 		nil, | ||||||
|  | 	) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type LogMessage struct { | ||||||
|  | 	ServiceName string                 `json:"sname"` | ||||||
|  | 	ServiceID   uuid.UUID              `json:"sid"` | ||||||
|  | 	Time        time.Time              `json:"time"` | ||||||
|  | 	Level       uint32                 `json:"level"` | ||||||
|  | 	Message     string                 `json:"message"` | ||||||
|  | 	Data        map[string]interface{} `json:"data"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func LogMessageFromEntry(sname string, sid uuid.UUID, e *log.Entry) *LogMessage { | ||||||
|  | 	return &LogMessage{ | ||||||
|  | 		ServiceName: sname, | ||||||
|  | 		ServiceID:   sid, | ||||||
|  | 		Time:        e.Time, | ||||||
|  | 		Level:       uint32(e.Level), | ||||||
|  | 		Message:     e.Message, | ||||||
|  | 		Data:        e.Data, | ||||||
|  | 	} | ||||||
|  | } | ||||||
		Reference in New Issue