mirror of
https://github.com/KevinMidboe/planetposen-images.git
synced 2025-10-28 21:00:12 +00:00
Implemented logger, write to file on disk
This commit is contained in:
@@ -3,15 +3,10 @@ package gcs
|
|||||||
import (
|
import (
|
||||||
"cloud.google.com/go/storage"
|
"cloud.google.com/go/storage"
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"github.com/kevinmidboe/planetposen-images/util"
|
"github.com/kevinmidboe/planetposen-images/util"
|
||||||
"google.golang.org/api/iterator"
|
"google.golang.org/api/iterator"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
// "errors"
|
|
||||||
"fmt"
|
|
||||||
// "github.com/dbmedialab/dearheart/event"
|
|
||||||
// "github.com/dbmedialab/dearheart/util"
|
|
||||||
// "path/filepath"
|
|
||||||
// "time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Client represents a GCS client with the functions that *we* need.
|
// Client represents a GCS client with the functions that *we* need.
|
||||||
@@ -73,9 +68,11 @@ func (c *clientImpl) FileLister(ctx context.Context) (files []string, err error)
|
|||||||
if err == iterator.Done {
|
if err == iterator.Done {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error from query %s", err)
|
return nil, fmt.Errorf("error from query %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
names = append(names, attrs.Name)
|
names = append(names, attrs.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,31 +2,29 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/kevinmidboe/planetposen-images/config"
|
"github.com/kevinmidboe/planetposen-images/config"
|
||||||
|
log "github.com/kevinmidboe/planetposen-images/logger"
|
||||||
"github.com/kevinmidboe/planetposen-images/server"
|
"github.com/kevinmidboe/planetposen-images/server"
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// log.SetFormatter(logrustic.NewFormatter("planetposen-images"))
|
logger := log.InitLogger()
|
||||||
|
logger.Info("Starting...")
|
||||||
log.Info("Starting...")
|
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
config, err := config.LoadConfig()
|
config, err := config.LoadConfig()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err.Error())
|
logger.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var s server.Server
|
var s server.Server
|
||||||
|
|
||||||
if err := s.Create(ctx, config); err != nil {
|
if err := s.Create(ctx, config); err != nil {
|
||||||
log.Fatal(err.Error())
|
logger.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.Serve(ctx); err != nil {
|
if err := s.Serve(ctx); err != nil {
|
||||||
log.Fatal(err.Error())
|
logger.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
110
logger/logger.go
Normal file
110
logger/logger.go
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
package logger
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Event stores messages to log later, from our standard interface
|
||||||
|
type Event struct {
|
||||||
|
id int
|
||||||
|
message string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplicationLogger enforces specific log message formats
|
||||||
|
type ApplicationLogger struct {
|
||||||
|
*logrus.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewLogger initializes the standard logger
|
||||||
|
func InitLogger() *ApplicationLogger {
|
||||||
|
var baseLogger = logrus.New()
|
||||||
|
var applicationLogger = &ApplicationLogger{baseLogger}
|
||||||
|
|
||||||
|
f, _ := os.OpenFile("/var/log/planetposen_logs/planetposen-images.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
||||||
|
|
||||||
|
applicationLogger.SetOutput(f)
|
||||||
|
applicationLogger.Formatter = &logrus.JSONFormatter{
|
||||||
|
TimestampFormat: time.RFC3339Nano,
|
||||||
|
FieldMap: logrus.FieldMap{
|
||||||
|
logrus.FieldKeyMsg: "message",
|
||||||
|
logrus.FieldKeyTime: "@timestamp",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return applicationLogger
|
||||||
|
}
|
||||||
|
|
||||||
|
// Declare variables to store log messages as new Events
|
||||||
|
var (
|
||||||
|
infoMessage = Event{1, "%s"}
|
||||||
|
invalidArgMessage = Event{2, "Invalid arg: %s"}
|
||||||
|
invalidArgValueMessage = Event{3, "Invalid value for argument: %s: %v"}
|
||||||
|
missingArgMessage = Event{4, "Missing arg: %s"}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (l *ApplicationLogger) Info(argumentName string) {
|
||||||
|
l.WithFields(logrus.Fields{
|
||||||
|
"application": "planetposen-images",
|
||||||
|
}).Infof(infoMessage.message, argumentName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ApplicationLogger) InfoWithPath(message string, path string) {
|
||||||
|
l.WithFields(logrus.Fields{
|
||||||
|
"application": "planetposen-images",
|
||||||
|
"path": path,
|
||||||
|
}).Info(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ApplicationLogger) InfoWithFilename(message string, filename string) {
|
||||||
|
l.WithFields(logrus.Fields{
|
||||||
|
"application": "planetposen-images",
|
||||||
|
"filename": filename,
|
||||||
|
}).Info(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ApplicationLogger) UploadSuccessMessage(path string, url string) {
|
||||||
|
l.WithFields(logrus.Fields{
|
||||||
|
"application": "planetposen-images",
|
||||||
|
"path": path,
|
||||||
|
"url": url,
|
||||||
|
}).Info("Uploaded and available")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ApplicationLogger) Error(message string, error error) {
|
||||||
|
l.WithFields(logrus.Fields{
|
||||||
|
"application": "planetposen-images",
|
||||||
|
"err": error,
|
||||||
|
}).Error(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ApplicationLogger) Fatal(error error) {
|
||||||
|
l.WithFields(logrus.Fields{
|
||||||
|
"application": "planetposen-images",
|
||||||
|
"err": error,
|
||||||
|
}).Fatal("Fatal application exception!")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ApplicationLogger) GoogleApiError(message string, error error) {
|
||||||
|
l.WithFields(logrus.Fields{
|
||||||
|
"application": "planetposen-images",
|
||||||
|
"go_package": "cloud.google.com/go/storage",
|
||||||
|
"err": error,
|
||||||
|
}).Error(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InvalidArg is a standard error message
|
||||||
|
func (l *ApplicationLogger) InvalidArg(argumentName string) {
|
||||||
|
l.Errorf(invalidArgMessage.message, argumentName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InvalidArgValue is a standard error message
|
||||||
|
func (l *ApplicationLogger) InvalidArgValue(argumentName string, argumentValue string) {
|
||||||
|
l.Errorf(invalidArgValueMessage.message, argumentName, argumentValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MissingArg is a standard error message
|
||||||
|
func (l *ApplicationLogger) MissingArg(argumentName string) {
|
||||||
|
l.Errorf(missingArgMessage.message, argumentName)
|
||||||
|
}
|
||||||
@@ -2,15 +2,16 @@ package handler
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
log "github.com/kevinmidboe/planetposen-images/logger"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var logger = log.InitLogger()
|
||||||
|
|
||||||
// handleError - Logs the error (if shouldLog is true), and outputs the error message (msg)
|
// handleError - Logs the error (if shouldLog is true), and outputs the error message (msg)
|
||||||
func handleError(w http.ResponseWriter, err error, msg string, statusCode int, shouldLog bool) {
|
func handleError(w http.ResponseWriter, err error, msg string, statusCode int, shouldLog bool) {
|
||||||
if shouldLog {
|
if shouldLog {
|
||||||
log.WithField("err", err).Error(msg)
|
logger.Error(msg, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
@@ -21,4 +22,19 @@ func handleError(w http.ResponseWriter, err error, msg string, statusCode int, s
|
|||||||
Error: msg,
|
Error: msg,
|
||||||
})
|
})
|
||||||
w.Write(errorJSON)
|
w.Write(errorJSON)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleGoogleApiError(w http.ResponseWriter, err error, msg string, statusCode int, shouldLog bool) {
|
||||||
|
if shouldLog {
|
||||||
|
logger.GoogleApiError(msg, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(statusCode)
|
||||||
|
errorJSON, _ := json.Marshal(struct {
|
||||||
|
Error string `json:"error"`
|
||||||
|
}{
|
||||||
|
Error: msg,
|
||||||
|
})
|
||||||
|
w.Write(errorJSON)
|
||||||
|
}
|
||||||
|
|||||||
@@ -40,16 +40,17 @@ func UploadImages(hostname string, gcsClient gcs.Client) http.HandlerFunc {
|
|||||||
filename := strings.ReplaceAll(fileHeader.Filename, "/", "-")
|
filename := strings.ReplaceAll(fileHeader.Filename, "/", "-")
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
|
logger.InfoWithFilename("uploading image with filename", filename)
|
||||||
writer, path, err := gcsClient.FileWriter(ctx, filename)
|
writer, path, err := gcsClient.FileWriter(ctx, filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handleError(w, err, "File unable to write file to gcs", http.StatusServiceUnavailable, true)
|
handleGoogleApiError(w, err, "File unable to write file to gcs", http.StatusServiceUnavailable, true)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer writer.Close()
|
defer writer.Close()
|
||||||
|
|
||||||
_, err = io.Copy(writer, file)
|
_, err = io.Copy(writer, file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handleError(w, err, "Error copying file to GCS", http.StatusInternalServerError, true)
|
handleGoogleApiError(w, err, "Error copying file to GCS", http.StatusInternalServerError, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
finalURL := util.ImageURL(hostname, string(path))
|
finalURL := util.ImageURL(hostname, string(path))
|
||||||
@@ -57,6 +58,7 @@ func UploadImages(hostname string, gcsClient gcs.Client) http.HandlerFunc {
|
|||||||
Path: string(path),
|
Path: string(path),
|
||||||
URL: finalURL,
|
URL: finalURL,
|
||||||
}
|
}
|
||||||
|
logger.UploadSuccessMessage(string(path), finalURL)
|
||||||
|
|
||||||
responseData, _ := json.Marshal(responseStruct)
|
responseData, _ := json.Marshal(responseStruct)
|
||||||
_, _ = w.Write(responseData)
|
_, _ = w.Write(responseData)
|
||||||
@@ -68,6 +70,9 @@ func FetchImage(gcsClient gcs.Client) http.HandlerFunc {
|
|||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
path := gcs.EncodedPath(mux.Vars(r)["path"])
|
path := gcs.EncodedPath(mux.Vars(r)["path"])
|
||||||
|
|
||||||
|
logger.InfoWithPath("Getting image", string(path))
|
||||||
|
|
||||||
if path == "" {
|
if path == "" {
|
||||||
handleError(w, nil, "missing image path ", http.StatusBadRequest, true)
|
handleError(w, nil, "missing image path ", http.StatusBadRequest, true)
|
||||||
return
|
return
|
||||||
@@ -75,7 +80,7 @@ func FetchImage(gcsClient gcs.Client) http.HandlerFunc {
|
|||||||
|
|
||||||
reader, err := gcsClient.FileReader(ctx, path)
|
reader, err := gcsClient.FileReader(ctx, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handleError(w, err, "error from gcs file reader ", http.StatusBadRequest, true)
|
handleGoogleApiError(w, err, "error from gcs file reader ", http.StatusBadRequest, true)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer reader.Close()
|
defer reader.Close()
|
||||||
@@ -87,6 +92,8 @@ func FetchImage(gcsClient gcs.Client) http.HandlerFunc {
|
|||||||
w.Header().Set("Content-Type", fmt.Sprintf("image/%s", extension[1:]))
|
w.Header().Set("Content-Type", fmt.Sprintf("image/%s", extension[1:]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.InfoWithFilename("found and returning file from bucket", string(filename))
|
||||||
|
|
||||||
_, err = io.Copy(w, reader)
|
_, err = io.Copy(w, reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handleError(w, err, "Couldn't copy the file from GCS ", http.StatusInternalServerError, true)
|
handleError(w, err, "Couldn't copy the file from GCS ", http.StatusInternalServerError, true)
|
||||||
@@ -96,11 +103,12 @@ func FetchImage(gcsClient gcs.Client) http.HandlerFunc {
|
|||||||
|
|
||||||
func ListImages(gcsClient gcs.Client) http.HandlerFunc {
|
func ListImages(gcsClient gcs.Client) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
logger.Info("Listing images")
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
|
|
||||||
files, err := gcsClient.FileLister(ctx)
|
files, err := gcsClient.FileLister(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handleError(w, err, "error from gcs file lister ", http.StatusBadRequest, true)
|
handleGoogleApiError(w, err, "error from gcs file lister ", http.StatusBadRequest, true)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
// Package server provides functionality to easily set up an HTTTP server.
|
// Package server provides functionality to easily set up an HTTTP server.
|
||||||
//
|
//
|
||||||
// Clients:
|
// Clients:
|
||||||
// Database
|
//
|
||||||
|
// Database
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
log "github.com/kevinmidboe/planetposen-images/logger"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
@@ -15,7 +17,6 @@ import (
|
|||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/kevinmidboe/planetposen-images/clients/gcs"
|
"github.com/kevinmidboe/planetposen-images/clients/gcs"
|
||||||
"github.com/kevinmidboe/planetposen-images/config"
|
"github.com/kevinmidboe/planetposen-images/config"
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Server holds the HTTP server, router, config and all clients.
|
// Server holds the HTTP server, router, config and all clients.
|
||||||
@@ -26,6 +27,8 @@ type Server struct {
|
|||||||
GCSClient gcs.Client
|
GCSClient gcs.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var logger = log.InitLogger()
|
||||||
|
|
||||||
// Create sets up the HTTP server, router and all clients.
|
// Create sets up the HTTP server, router and all clients.
|
||||||
// Returns an error if an error occurs.
|
// Returns an error if an error occurs.
|
||||||
func (s *Server) Create(ctx context.Context, config *config.Config) error {
|
func (s *Server) Create(ctx context.Context, config *config.Config) error {
|
||||||
@@ -68,17 +71,17 @@ func (s *Server) Serve(ctx context.Context) error {
|
|||||||
|
|
||||||
<-stop
|
<-stop
|
||||||
|
|
||||||
log.Info("Shutdown signal received")
|
logger.Info("Shutdown signal received")
|
||||||
|
|
||||||
if err := s.HTTP.Shutdown(ctx); err != nil {
|
if err := s.HTTP.Shutdown(ctx); err != nil {
|
||||||
log.Error(err.Error())
|
logger.Error("Error causing shutdown", err)
|
||||||
}
|
}
|
||||||
}(ctx, s)
|
}(ctx, s)
|
||||||
|
|
||||||
log.Infof("Ready at: %s", s.Config.Port)
|
logger.Info("Ready at: " + s.Config.Port)
|
||||||
|
|
||||||
if err := s.HTTP.ListenAndServe(); err != http.ErrServerClosed {
|
if err := s.HTTP.ListenAndServe(); err != http.ErrServerClosed {
|
||||||
log.Fatalf(err.Error())
|
logger.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
Reference in New Issue
Block a user