github.com/vicanso/pike@v1.0.1-0.20210630235453-9099e041f6ec/main.go (about) 1 package main 2 3 import ( 4 "bytes" 5 "fmt" 6 "io/ioutil" 7 "net/http" 8 "os" 9 "os/signal" 10 "syscall" 11 12 "github.com/spf13/cobra" 13 "github.com/vicanso/pike/app" 14 "github.com/vicanso/pike/cache" 15 "github.com/vicanso/pike/compress" 16 "github.com/vicanso/pike/config" 17 "github.com/vicanso/pike/location" 18 "github.com/vicanso/pike/log" 19 _ "github.com/vicanso/pike/schedule" 20 "github.com/vicanso/pike/server" 21 "github.com/vicanso/pike/store" 22 "github.com/vicanso/pike/upstream" 23 "go.uber.org/automaxprocs/maxprocs" 24 "go.uber.org/zap" 25 ) 26 27 var ( 28 version = "dev" 29 commit = "none" 30 date = "unknown" 31 builtBy = "unknown" 32 ) 33 34 // alarmURL 告警发送的地址 35 var alarmURL string 36 var alarmTemplate string 37 38 func init() { 39 40 err := runCMD() 41 if err != nil { 42 panic(err) 43 } 44 // 如果是help cmd,则 45 if isHelpCmd() { 46 os.Exit(0) 47 return 48 } 49 _, _ = maxprocs.Set(maxprocs.Logger(func(format string, args ...interface{}) { 50 value := fmt.Sprintf(format, args...) 51 log.Default().Info(value) 52 })) 53 app.SetBuildInfo(date, commit, version, builtBy) 54 hostname, _ := os.Hostname() 55 alarmTemplate = `{ 56 "application": "pike", 57 "hostname": "` + hostname + `", 58 "category": "%s", 59 "message": "%s" 60 }` 61 } 62 63 // doAlarm 发送告警 64 func doAlarm(category, message string) { 65 if alarmURL == "" { 66 return 67 } 68 data := fmt.Sprintf(alarmTemplate, category, message) 69 resp, err := http.Post(alarmURL, "application/json", bytes.NewBufferString(data)) 70 if err != nil { 71 log.Default().Error("do alarm fail", 72 zap.Error(err), 73 ) 74 return 75 } 76 defer resp.Body.Close() 77 result, _ := ioutil.ReadAll(resp.Body) 78 if resp.StatusCode >= 400 { 79 log.Default().Error("do alarm fail", 80 zap.Int("status", resp.StatusCode), 81 zap.String("result", string(result)), 82 ) 83 } 84 } 85 86 func update() (err error) { 87 pikeConfig, err := config.Read() 88 if err != nil { 89 return 90 } 91 // 重置压缩列表 92 compress.Reset(pikeConfig.Compresses) 93 // 重置默认dispatcher列表 94 cache.ResetDispatchers(pikeConfig.Caches) 95 // 重置默认的upstream列表 96 upstream.ResetWithOnStats(pikeConfig.Upstreams, func(si upstream.StatusInfo) { 97 log.Default().Info("upstream status change", 98 zap.String("name", si.Name), 99 zap.String("status", si.Status), 100 zap.String("addr", si.URL), 101 ) 102 103 if si.Status == "sick" { 104 message := fmt.Sprintf("%s is %s, addr: %s", si.Name, si.Status, si.URL) 105 go doAlarm("upstream", message) 106 } 107 }) 108 // 重置location列表 109 location.Reset(pikeConfig.Locations) 110 111 server.Reset(pikeConfig.Servers) 112 return server.Start() 113 } 114 115 func startAdminServer(addr string) error { 116 pikeConfig, err := config.Read() 117 if err != nil { 118 return err 119 } 120 return server.StartAdminServer(server.AdminServerConfig{ 121 Addr: addr, 122 User: pikeConfig.Admin.User, 123 Password: pikeConfig.Admin.Password, 124 }) 125 } 126 127 // runCMD 解析各命令参数 128 func runCMD() error { 129 configURL := "" 130 adminAddr := "" 131 logOutputPath := "" 132 133 var rootCmd = &cobra.Command{ 134 Use: "pike", 135 Short: "Pike is a http cache server", 136 PreRun: func(cmd *cobra.Command, args []string) { 137 if logOutputPath != "" { 138 log.SetOutputPath(logOutputPath) 139 } 140 // 初始化配置 141 err := config.InitDefaultClient(configURL) 142 if err != nil { 143 panic(err) 144 } 145 }, 146 Run: func(cmd *cobra.Command, args []string) { 147 148 if adminAddr != "" { 149 go func() { 150 err := startAdminServer(adminAddr) 151 if err != nil { 152 log.Default().Error("start admin server fail", 153 zap.String("addr", adminAddr), 154 zap.Error(err), 155 ) 156 go doAlarm("admin", adminAddr+", "+err.Error()) 157 } 158 }() 159 } 160 run() 161 }, 162 } 163 // 配置文件地址 164 rootCmd.Flags().StringVar(&configURL, "config", "pike.yml", "The config of pike, support etcd or file, etcd://user:pass@192.168.1.2:2379,192.168.1.3:2379/pike or /opt/pike.yml") 165 // 管理后台地址 166 rootCmd.Flags().StringVar(&adminAddr, "admin", "", "The address of admin web page, e.g.: :9013") 167 // 告警发送地址 168 rootCmd.Flags().StringVar(&alarmURL, "alarm", "", "The alarm request url, alarm will post to the url, e.g.: http://192.168.1.2:3000/alarms") 169 // 日志文件 170 rootCmd.Flags().StringVar(&logOutputPath, "log", "", "The log path, e.g.: /var/pike.log or lumberjack:///tmp/pike.log?maxSize=100&maxAge=1&compress=true") 171 172 return rootCmd.Execute() 173 } 174 175 func run() { 176 logger := log.Default() 177 178 go config.Watch(func() { 179 err := update() 180 if err != nil { 181 logger.Error("update config fail", 182 zap.Error(err), 183 ) 184 go doAlarm("config", err.Error()) 185 } else { 186 logger.Info("update config success") 187 } 188 }) 189 190 err := update() 191 if err != nil { 192 panic(err) 193 } 194 } 195 196 func isHelpCmd() bool { 197 for _, arg := range os.Args { 198 if arg == "-h" || arg == "--help" { 199 return true 200 } 201 } 202 return false 203 } 204 205 // isDev 判断是否开发环境 206 func isDev() bool { 207 return os.Getenv("GO_ENV") == "dev" 208 } 209 210 func main() { 211 defer config.Close() 212 defer store.Close() 213 214 log.Default().Info("pike is running") 215 c := make(chan os.Signal, 1) 216 signal.Notify(c, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) 217 for si := range c { 218 log.Default().Info("closing", 219 zap.String("signal", si.String()), 220 ) 221 // 如果非开发环境,则需要close所有的server 222 if !isDev() { 223 server.Close() 224 } 225 os.Exit(0) 226 } 227 }