Create a Golang application that serves as a proxy server, forwarding incoming HTTP requests to another specified server while logging request and response details to a MySQL database. Implement rate limiting to prevent abuse of the proxy server.
PLAINFORMAT
package main

import (
	"database/sql"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"time"

	"github.com/didip/tollbooth"
	"github.com/didip/tollbooth/limiter"
	_ "github.com/go-sql-driver/mysql"
)

const targetServer = "http://example.com"
const dsn = "username:password@tcp(localhost:3306)/dbname"

func main() {
	db, err := sql.Open("mysql", dsn)
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	lmt := tollbooth.NewLimiter(1, &limiter.ExpirableOptions{DefaultExpirationTTL: time.Hour})
	lmt.SetIPLookups([]string{"RemoteAddr", "X-Forwarded-For", "X-Real-IP"})
	http.Handle("/", tollbooth.LimitFuncHandler(lmt, func(w http.ResponseWriter, r *http.Request) {
		startTime := time.Now()
		resp, err := http.DefaultTransport.RoundTrip(r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusBadGateway)
			return
		}

		for key, values := range resp.Header {
			for _, value := range values {
				w.Header().Add(key, value)
			}
		}
		bodyBytes, _ := ioutil.ReadAll(resp.Body)
		w.WriteHeader(resp.StatusCode)
		w.Write(bodyBytes)

		duration := time.Since(startTime)
		go logRequest(db, r, resp, duration)
	}))

	log.Println("Starting proxy server on :8080")
	log.Fatal(http.ListenAndServe(":8080", nil))
}

func logRequest(db *sql.DB, r *http.Request, resp *http.Response, duration time.Duration) {
	query := `
		INSERT INTO request_log (client_ip, method, path, user_agent, status_code, response_time)
		VALUES (?, ?, ?, ?, ?, ?)
	`
	stmt, err := db.Prepare(query)
	if err != nil {
		log.Println("Error preparing query:", err)
		return
	}
	defer stmt.Close()

	clientIP := r.Header.Get("X-Forwarded-For")
	if clientIP == "" {
		clientIP = r.RemoteAddr
	}
	userAgent := r.UserAgent()
	_, err = stmt.Exec(clientIP, r.Method, r.URL.Path, userAgent, resp.StatusCode, duration.Milliseconds())
	if err != nil {
		log.Println("Error executing query:", err)
	}
}