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