feature/adding-log-file #1
			
				
			
		
		
		
	| 
						 | 
				
			
			@ -0,0 +1,52 @@
 | 
			
		|||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const CONFIG_LOG string = "/var/lib/gocustomurls/"
 | 
			
		||||
 | 
			
		||||
type ConfigFile struct {
 | 
			
		||||
	Mappings []struct {
 | 
			
		||||
		Protocol  string `json:"protocol"`
 | 
			
		||||
		VanityUrl string `json:"vanity_url"`
 | 
			
		||||
		RealUrl   string `json:"real_url"`
 | 
			
		||||
	} `json:"mappings"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// isFile - check if fp is a valid file
 | 
			
		||||
func isFile(fp string) bool {
 | 
			
		||||
	info, err := os.Stat(fp)
 | 
			
		||||
	if os.IsNotExist(err) || !info.Mode().IsRegular() {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// load mapping file
 | 
			
		||||
func LoadFile() (ConfigFile, error) {
 | 
			
		||||
	var mapping ConfigFile
 | 
			
		||||
	dirname, err := os.UserConfigDir()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return mapping, err
 | 
			
		||||
	}
 | 
			
		||||
	configFilePath := filepath.Join(dirname, "gocustomurls/config.json")
 | 
			
		||||
	ok := isFile(configFilePath)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return mapping, fmt.Errorf("%s/gocustomurls/config.json file is not found", dirname)
 | 
			
		||||
	}
 | 
			
		||||
	configFile, err := os.Open(configFilePath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return mapping, err
 | 
			
		||||
	}
 | 
			
		||||
	defer configFile.Close()
 | 
			
		||||
 | 
			
		||||
	err = json.NewDecoder(configFile).Decode(&mapping)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return mapping, err
 | 
			
		||||
	}
 | 
			
		||||
	return mapping, nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,148 @@
 | 
			
		|||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"log"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// some headers not worth logging
 | 
			
		||||
var (
 | 
			
		||||
	hdrsToNotLog = []string{
 | 
			
		||||
		"Accept-Language",
 | 
			
		||||
		"Cache-Control",
 | 
			
		||||
		"Cf-Ray",
 | 
			
		||||
		"CF-Visitor",
 | 
			
		||||
		"CF-Connecting-IP",
 | 
			
		||||
		"Cdn-Loop",
 | 
			
		||||
		"Cookie",
 | 
			
		||||
		"Connection",
 | 
			
		||||
		"Dnt",
 | 
			
		||||
		"If-Modified-Since",
 | 
			
		||||
		"Sec-Fetch-Dest",
 | 
			
		||||
		"Sec-Ch-Ua-Mobile",
 | 
			
		||||
		// "Sec-Ch-Ua",
 | 
			
		||||
		"Sec-Ch-Ua-Platform",
 | 
			
		||||
		"Sec-Fetch-Site",
 | 
			
		||||
		"Sec-Fetch-Mode",
 | 
			
		||||
		"Sec-Fetch-User",
 | 
			
		||||
		"Upgrade-Insecure-Requests",
 | 
			
		||||
		"X-Request-Start",
 | 
			
		||||
		"X-Forwarded-For",
 | 
			
		||||
		"X-Forwarded-Proto",
 | 
			
		||||
		"X-Forwarded-Host",
 | 
			
		||||
	}
 | 
			
		||||
	hdrsToNotLogMap map[string]bool
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type LogFile struct {
 | 
			
		||||
	handle *os.File
 | 
			
		||||
	logger *log.Logger
 | 
			
		||||
	path   string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type LogFileRec struct {
 | 
			
		||||
	Method string `json:"method"`
 | 
			
		||||
	IpAddr string `json:"ipAddr"`
 | 
			
		||||
	Url    string `json:"url"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newFileLogger(path string) (*LogFile, error) {
 | 
			
		||||
	f, err := os.OpenFile(path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return &LogFile{
 | 
			
		||||
		handle: f,
 | 
			
		||||
		logger: log.New(f, "", 0),
 | 
			
		||||
		path:   path,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *LogFile) Close() error {
 | 
			
		||||
	if f == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	err := f.handle.Close()
 | 
			
		||||
	f.handle = nil
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func extractFirstFragment(header *http.Header, headerName string) string {
 | 
			
		||||
	s := header.Get(headerName)
 | 
			
		||||
	if len(strings.TrimSpace(s)) == 0 {
 | 
			
		||||
		return s
 | 
			
		||||
	}
 | 
			
		||||
	fragments := strings.Split(s, ",")
 | 
			
		||||
	return strings.TrimSpace(fragments[0])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Get Ip Address of the client
 | 
			
		||||
func extractIpAddress(r *http.Request) string {
 | 
			
		||||
	var ipAddr string
 | 
			
		||||
	if r == nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
	possibleIpHeaders := []string{"CF-Connecting-IP", "X-Real-Ip", "X-Forwarded-For"}
 | 
			
		||||
	for _, header := range possibleIpHeaders {
 | 
			
		||||
		ipAddr = extractFirstFragment(&r.Header, header)
 | 
			
		||||
		if len(strings.TrimSpace(ipAddr)) != 0 {
 | 
			
		||||
			return ipAddr
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// pull ip from Request.RemoteAddr
 | 
			
		||||
	if len(strings.TrimSpace(r.RemoteAddr)) != 0 {
 | 
			
		||||
		index := strings.LastIndex(r.RemoteAddr, ";")
 | 
			
		||||
		if index == -1 {
 | 
			
		||||
			return r.RemoteAddr
 | 
			
		||||
		}
 | 
			
		||||
		ipAddr = r.RemoteAddr[:index]
 | 
			
		||||
	}
 | 
			
		||||
	return ipAddr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func canSkipExtraHeaders(r *http.Request) bool {
 | 
			
		||||
	ref := r.Header.Get("Referer")
 | 
			
		||||
	if len(strings.TrimSpace(ref)) == 0 {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	return strings.Contains(ref, r.Host)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func shouldLogHeader(s string) bool {
 | 
			
		||||
	if hdrsToNotLogMap == nil {
 | 
			
		||||
		hdrsToNotLogMap = map[string]bool{}
 | 
			
		||||
		for _, h := range hdrsToNotLog {
 | 
			
		||||
			h = strings.ToLower(h)
 | 
			
		||||
			hdrsToNotLogMap[h] = true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	s = strings.ToLower(s)
 | 
			
		||||
	return !hdrsToNotLogMap[s]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *LogFile) WriteLog(r *http.Request) error {
 | 
			
		||||
	if f == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	var rec = make(map[string]string)
 | 
			
		||||
	rec["method"] = r.Method
 | 
			
		||||
	rec["requestUri"] = r.RequestURI
 | 
			
		||||
	rec["Host"] = r.Host
 | 
			
		||||
	rec["ipAddr"] = extractIpAddress(r)
 | 
			
		||||
	if !canSkipExtraHeaders(r) {
 | 
			
		||||
		for key, val := range r.Header {
 | 
			
		||||
			if shouldLogHeader(key) && len(val) > 0 {
 | 
			
		||||
				rec[key] = val[0]
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	b, err := json.Marshal(rec)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	f.logger.Println(string(b))
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue