199 lines
4.7 KiB
Go
199 lines
4.7 KiB
Go
package main // import "amuz.es/src/infra/cpu_ctrl"
|
|
|
|
import (
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
"fmt"
|
|
zlog "amuz.es/src/infra/goutils/logger/zap"
|
|
"go.uber.org/zap/zapcore"
|
|
"go.uber.org/multierr"
|
|
"amuz.es/src/infra/goutils/logger/rotater"
|
|
"amuz.es/src/infra/goutils/handler"
|
|
"amuz.es/src/infra/cpu_ctrl/daemon"
|
|
"amuz.es/src/infra/cpu_ctrl/producer"
|
|
"amuz.es/src/infra/cpu_ctrl/consumer"
|
|
"go.uber.org/zap"
|
|
"errors"
|
|
)
|
|
|
|
func finalCloser() {
|
|
if err := recover(); err != nil {
|
|
fmt.Fprintln(os.Stderr, err.(error).Error())
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
// 로그 초기화
|
|
func initLogger() func() {
|
|
// 로깅설정
|
|
formatter := zapcore.NewConsoleEncoder(zlog.LogCommonFormat)
|
|
|
|
level := zap.InfoLevel
|
|
if *verbose {
|
|
level = zap.DebugLevel
|
|
}
|
|
// 전역 로거 초기화
|
|
var err error
|
|
logger, err = zlog.Init(
|
|
true,
|
|
formatter,
|
|
name,
|
|
"Stderr",
|
|
"",
|
|
nil,
|
|
level,
|
|
)
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
// 로깅종료 및 exitcode 설정
|
|
return func() {}
|
|
}
|
|
|
|
// 애플리케이션이 종료를 위해 대기하는 부분
|
|
func initContext(handler *handler.Handler) (func(), func()) {
|
|
exitSignal := make(chan os.Signal, 1)
|
|
// return waiter
|
|
return func() {
|
|
daemon.NotifyDaemon(daemon.DaemonStarted)
|
|
// 시그널 처리
|
|
signal.Notify(exitSignal, syscall.SIGINT, syscall.SIGTERM, syscall.SIGUSR1)
|
|
for {
|
|
select {
|
|
case <-handler.Done():
|
|
logger.Info("self destruct to close this application")
|
|
return
|
|
case initialErr := <-handler.Error():
|
|
// 복구불가능한 에러(들) 모아서 넘겨주는 부분
|
|
merged := initialErr
|
|
logger.Error("main: ", initialErr)
|
|
for {
|
|
select {
|
|
case anotherErr := <-handler.Error():
|
|
merged = multierr.Append(merged, anotherErr)
|
|
logger.Error("main: ", anotherErr)
|
|
default:
|
|
// panic을 발생시켜 컨텍스트를 에러를 전달한다.
|
|
panic(merged)
|
|
}
|
|
}
|
|
case sysSignal := <-exitSignal:
|
|
//handle signal
|
|
switch sysSignal {
|
|
case syscall.SIGUSR1:
|
|
rotater.Rotate()
|
|
default:
|
|
logger.Info(sysSignal.String(), " received")
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}, // return closer
|
|
func() {
|
|
daemon.NotifyDaemon(daemon.DaemonStopping)
|
|
logger.Info("main: main context waiting..")
|
|
// http 서버 기다린다.
|
|
handler.GracefulWait()
|
|
close(exitSignal)
|
|
}
|
|
}
|
|
|
|
// 메인 웹서버 초기화
|
|
func initProcessor(handler *handler.Handler) func() {
|
|
|
|
FanoutOsMetricInfo := func(sender <-chan producer.OSMetricInfo, receivers ...chan<- producer.OSMetricInfo) {
|
|
defer func() {
|
|
for _, receiver := range receivers {
|
|
close(receiver)
|
|
}
|
|
if err := recover(); err != nil {
|
|
handler.NotifyError(err.(error))
|
|
}
|
|
}()
|
|
for metric := range sender {
|
|
for _, receiver := range receivers {
|
|
select {
|
|
case receiver <- metric:
|
|
default:
|
|
logger.Warn("Some OSMetricInfo consumer blocked!")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
FanoutSpeed := func(sender <-chan producer.FanspeedInfo, receivers ...chan<- producer.FanspeedInfo) {
|
|
defer func() {
|
|
for _, receiver := range receivers {
|
|
close(receiver)
|
|
}
|
|
if err := recover(); err != nil {
|
|
handler.NotifyError(err.(error))
|
|
}
|
|
}()
|
|
for speed := range sender {
|
|
for _, receiver := range receivers {
|
|
select {
|
|
case receiver <- speed:
|
|
default:
|
|
logger.Warn("Some Fanspeed consumer blocked!")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
FanoutTempeture := func(sender <-chan producer.TempetureInfo, receivers ...chan<- producer.TempetureInfo) {
|
|
defer func() {
|
|
|
|
for _, receiver := range receivers {
|
|
close(receiver)
|
|
}
|
|
if err := recover(); err != nil {
|
|
handler.NotifyError(err.(error))
|
|
}
|
|
}()
|
|
for tempeture := range sender {
|
|
for _, receiver := range receivers {
|
|
select {
|
|
case receiver <- tempeture:
|
|
default:
|
|
logger.Warn("Some Tempeture consumer blocked!")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
processorCount := producer.GetProcessorCount()
|
|
if processorCount == 0 {
|
|
panic(errors.New("cpu not found!"))
|
|
}
|
|
|
|
osMetricInfoChan := producer.NewOsMetric(
|
|
handler,
|
|
*SampleInterval,
|
|
)
|
|
tempetureInfoChan, fanspeedChan := producer.AggregateProcessorChannel(
|
|
handler,
|
|
*SampleInterval, processorCount,
|
|
*P, *I, *D,
|
|
*SetPoint,
|
|
)
|
|
simpleLogger := consumer.NewSampleOSLogger(*SampleInterval, handler)
|
|
fanController := consumer.NewFanControl(processorCount, *SampleInterval, handler)
|
|
metricLogger := consumer.NewInfluxMetric((*InfluxHost).String(), processorCount, handler)
|
|
|
|
handler.IncreaseWait()
|
|
go simpleLogger.StartControl()
|
|
handler.IncreaseWait()
|
|
go fanController.StartControl()
|
|
handler.IncreaseWait()
|
|
go metricLogger.StartLogging()
|
|
|
|
go FanoutOsMetricInfo(osMetricInfoChan, simpleLogger.Consumer())
|
|
go FanoutTempeture(tempetureInfoChan, metricLogger.TempetureConsumer())
|
|
go FanoutSpeed(fanspeedChan, fanController.Consumer(), metricLogger.FanSpeedConsumer())
|
|
|
|
return func() {}
|
|
}
|