package main import ( "fmt" "log/slog" "net/http" "net/http/httputil" "net/url" "time" "backend/src/internal/config" "backend/src/internal/logging" ) const ( AppName = "Ollama Proxy" AppVersion = "1.0.0" ) func main() { logger := logging.New("info") slog.SetDefault(logger) logger.Info(fmt.Sprintf("Starting %s version %s", AppName, AppVersion)) cfg, err := config.LoadConfig(logger) if err != nil { logger.Error("Ошибка конфигурации", "error", err) return } level := logging.ParseLevel(cfg.LoggingConfig.Level) if level != slog.LevelInfo { logger.Info("Уровень логирования из env", "level", level.String()) } logger = logging.New(cfg.LoggingConfig.Level) slog.SetDefault(logger) cfg.LoggingConfig.Instance = logger target, err := url.Parse(cfg.BackendURL) if err != nil { logger.Error("Неверный URL бэкенда", "error", err) return } proxy := &httputil.ReverseProxy{ Rewrite: func(r *httputil.ProxyRequest) { r.SetURL(target) r.Out.Host = target.Host }, ErrorHandler: func(w http.ResponseWriter, r *http.Request, err error) { logger.Error("Ошибка прокси", "method", r.Method, "path", r.URL.Path, "error", err) http.Error(w, "Bad Gateway", http.StatusBadGateway) }, } handler := loggingMiddleware(logger, proxy) logger.Info("Прокси запущен", "addr", cfg.ListenAddr, "backend", cfg.BackendURL) if err := http.ListenAndServe(cfg.ListenAddr, handler); err != nil { logger.Error("Ошибка сервера", "error", err) } } func loggingMiddleware(logger *slog.Logger, next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() rw := &responseWriter{ResponseWriter: w, status: http.StatusOK} next.ServeHTTP(rw, r) logger.Info("запрос", "method", r.Method, "path", r.URL.Path, "status", rw.status, "duration", time.Since(start).String(), ) }) } type responseWriter struct { http.ResponseWriter status int } func (rw *responseWriter) WriteHeader(code int) { rw.status = code rw.ResponseWriter.WriteHeader(code) }