Add option to disable request logging per endpoint

This commit is contained in:
Toby Chui
2025-10-23 22:41:09 +08:00
parent f9ef648664
commit 9d0a2a94f7
9 changed files with 70 additions and 28 deletions

View File

@@ -48,7 +48,7 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
//Check if this is a redirection url
if h.Parent.Option.RedirectRuleTable.IsRedirectable(r) {
statusCode := h.Parent.Option.RedirectRuleTable.HandleRedirect(w, r)
h.Parent.logRequest(r, statusCode != 500, statusCode, "redirect", r.Host, "")
h.Parent.logRequest(r, statusCode != 500, statusCode, "redirect", r.Host, "", nil)
return
}
@@ -70,7 +70,7 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
//Use default rule
ruleID = "default"
}
if h.handleAccessRouting(ruleID, w, r) {
if h.handleAccessRouting(ruleID, w, r, sep) {
//Request handled by subroute
return
}
@@ -79,7 +79,9 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if sep.RequireRateLimit {
err := h.handleRateLimitRouting(w, r, sep)
if err != nil {
h.Parent.Option.Logger.LogHTTPRequest(r, "host", 307, r.Host, "")
if !sep.DisableLogging {
h.Parent.Option.Logger.LogHTTPRequest(r, "host", 307, r.Host, "")
}
return
}
}
@@ -109,7 +111,9 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if potentialProxtEndpoint != nil && !potentialProxtEndpoint.Disabled {
//Missing tailing slash. Redirect to target proxy endpoint
http.Redirect(w, r, r.RequestURI+"/", http.StatusTemporaryRedirect)
h.Parent.Option.Logger.LogHTTPRequest(r, "redirect", 307, r.Host, "")
if !sep.DisableLogging {
h.Parent.Option.Logger.LogHTTPRequest(r, "redirect", 307, r.Host, "")
}
return
}
}
@@ -124,7 +128,7 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
*/
//Root access control based on default rule
blocked := h.handleAccessRouting("default", w, r)
blocked := h.handleAccessRouting("default", w, r, h.Parent.Root)
if blocked {
return
}
@@ -210,19 +214,19 @@ func (h *ProxyHandler) handleRootRouting(w http.ResponseWriter, r *http.Request)
}
hostname := parsedURL.Hostname()
if hostname == domainOnly {
h.Parent.logRequest(r, false, 500, "root-redirect", domainOnly, "")
h.Parent.logRequest(r, false, 500, "root-redirect", domainOnly, "", h.Parent.Root)
http.Error(w, "Loopback redirects due to invalid settings", 500)
return
}
h.Parent.logRequest(r, false, 307, "root-redirect", domainOnly, "")
h.Parent.logRequest(r, false, 307, "root-redirect", domainOnly, "", h.Parent.Root)
http.Redirect(w, r, redirectTarget, http.StatusTemporaryRedirect)
case DefaultSite_NotFoundPage:
//Serve the not found page, use template if exists
h.serve404PageWithTemplate(w, r)
case DefaultSite_NoResponse:
//No response. Just close the connection
h.Parent.logRequest(r, false, 444, "root-no_resp", domainOnly, "")
h.Parent.logRequest(r, false, 444, "root-no_resp", domainOnly, "", h.Parent.Root)
hijacker, ok := w.(http.Hijacker)
if !ok {
w.WriteHeader(http.StatusNoContent)
@@ -236,11 +240,11 @@ func (h *ProxyHandler) handleRootRouting(w http.ResponseWriter, r *http.Request)
conn.Close()
case DefaultSite_TeaPot:
//I'm a teapot
h.Parent.logRequest(r, false, 418, "root-teapot", domainOnly, "")
h.Parent.logRequest(r, false, 418, "root-teapot", domainOnly, "", h.Parent.Root)
http.Error(w, "I'm a teapot", http.StatusTeapot)
default:
//Unknown routing option. Send empty response
h.Parent.logRequest(r, false, 544, "root-unknown", domainOnly, "")
h.Parent.logRequest(r, false, 544, "root-unknown", domainOnly, "", h.Parent.Root)
http.Error(w, "544 - No Route Defined", 544)
}
}

View File

@@ -13,7 +13,7 @@ import (
// Handle access check (blacklist / whitelist), return true if request is handled (aka blocked)
// if the return value is false, you can continue process the response writer
func (h *ProxyHandler) handleAccessRouting(ruleID string, w http.ResponseWriter, r *http.Request) bool {
func (h *ProxyHandler) handleAccessRouting(ruleID string, w http.ResponseWriter, r *http.Request, sep *ProxyEndpoint) bool {
accessRule, err := h.Parent.Option.AccessController.GetAccessRuleByID(ruleID)
if err != nil {
//Unable to load access rule. Target rule not found?
@@ -25,7 +25,7 @@ func (h *ProxyHandler) handleAccessRouting(ruleID string, w http.ResponseWriter,
isBlocked, blockedReason := accessRequestBlocked(accessRule, h.Parent.Option.WebDirectory, w, r)
if isBlocked {
h.Parent.logRequest(r, false, 403, blockedReason, r.Host, "")
h.Parent.logRequest(r, false, 403, blockedReason, r.Host, "", sep)
}
return isBlocked
}

View File

@@ -156,7 +156,7 @@ func (router *Router) StartProxyService() error {
if err != nil {
http.ServeFile(w, r, "./web/hosterror.html")
router.Option.Logger.PrintAndLog("dprouter", "failed to get upstream for hostname", err)
router.logRequest(r, false, 404, "vdir-http", r.Host, "")
router.logRequest(r, false, 404, "vdir-http", r.Host, "", sep)
}
endpointProxyRewriteRules := GetDefaultHeaderRewriteRules()

View File

@@ -141,7 +141,7 @@ func (h *ProxyHandler) upstreamHostSwap(w http.ResponseWriter, r *http.Request,
} else {
//Endpoint disabled, return 503
http.ServeFile(w, r, "./web/rperror.html")
h.Parent.logRequest(r, false, 521, "host-http", r.Host, upstreamHostname)
h.Parent.logRequest(r, false, 521, "host-http", r.Host, upstreamHostname, currentTarget)
}
return true
}
@@ -159,7 +159,7 @@ func (h *ProxyHandler) hostRequest(w http.ResponseWriter, r *http.Request, targe
if err != nil {
http.ServeFile(w, r, "./web/rperror.html")
h.Parent.Option.Logger.PrintAndLog("proxy", "Failed to assign an upstream for this request", err)
h.Parent.logRequest(r, false, 521, "subdomain-http", r.URL.Hostname(), r.Host)
h.Parent.logRequest(r, false, 521, "subdomain-http", r.URL.Hostname(), r.Host, target)
return
}
@@ -187,7 +187,7 @@ func (h *ProxyHandler) hostRequest(w http.ResponseWriter, r *http.Request, targe
if selectedUpstream.RequireTLS {
u, _ = url.Parse("wss://" + wsRedirectionEndpoint + requestURL)
}
h.Parent.logRequest(r, true, 101, "host-websocket", reqHostname, selectedUpstream.OriginIpOrDomain)
h.Parent.logRequest(r, true, 101, "host-websocket", reqHostname, selectedUpstream.OriginIpOrDomain, target)
if target.HeaderRewriteRules == nil {
target.HeaderRewriteRules = GetDefaultHeaderRewriteRules()
@@ -249,18 +249,18 @@ func (h *ProxyHandler) hostRequest(w http.ResponseWriter, r *http.Request, targe
if err != nil {
if errors.As(err, &dnsError) {
http.ServeFile(w, r, "./web/hosterror.html")
h.Parent.logRequest(r, false, 404, "host-http", reqHostname, upstreamHostname)
h.Parent.logRequest(r, false, 404, "host-http", reqHostname, upstreamHostname, target)
} else if errors.Is(err, context.Canceled) {
//Request canceled by client, usually due to manual refresh before page load
http.Error(w, "Request canceled", http.StatusRequestTimeout)
h.Parent.logRequest(r, false, http.StatusRequestTimeout, "host-http", reqHostname, upstreamHostname)
h.Parent.logRequest(r, false, http.StatusRequestTimeout, "host-http", reqHostname, upstreamHostname, target)
} else {
http.ServeFile(w, r, "./web/rperror.html")
h.Parent.logRequest(r, false, 521, "host-http", reqHostname, upstreamHostname)
h.Parent.logRequest(r, false, 521, "host-http", reqHostname, upstreamHostname, target)
}
}
h.Parent.logRequest(r, true, statusCode, "host-http", reqHostname, upstreamHostname)
h.Parent.logRequest(r, true, statusCode, "host-http", reqHostname, upstreamHostname, target)
}
// Handle vdir type request
@@ -286,7 +286,7 @@ func (h *ProxyHandler) vdirRequest(w http.ResponseWriter, r *http.Request, targe
target.parent.HeaderRewriteRules = GetDefaultHeaderRewriteRules()
}
h.Parent.logRequest(r, true, 101, "vdir-websocket", r.Host, target.Domain)
h.Parent.logRequest(r, true, 101, "vdir-websocket", r.Host, target.Domain, target.parent)
wspHandler := websocketproxy.NewProxy(u, websocketproxy.Options{
SkipTLSValidation: target.SkipCertValidations,
SkipOriginCheck: true, //You should not use websocket via virtual directory. But keep this to true for compatibility
@@ -342,19 +342,25 @@ func (h *ProxyHandler) vdirRequest(w http.ResponseWriter, r *http.Request, targe
if errors.As(err, &dnsError) {
http.ServeFile(w, r, "./web/hosterror.html")
log.Println(err.Error())
h.Parent.logRequest(r, false, 404, "vdir-http", reqHostname, target.Domain)
h.Parent.logRequest(r, false, 404, "vdir-http", reqHostname, target.Domain, target.parent)
} else {
http.ServeFile(w, r, "./web/rperror.html")
log.Println(err.Error())
h.Parent.logRequest(r, false, 521, "vdir-http", reqHostname, target.Domain)
h.Parent.logRequest(r, false, 521, "vdir-http", reqHostname, target.Domain, target.parent)
}
}
h.Parent.logRequest(r, true, statusCode, "vdir-http", reqHostname, target.Domain)
h.Parent.logRequest(r, true, statusCode, "vdir-http", reqHostname, target.Domain, target.parent)
}
// This logger collect data for the statistical analysis. For log to file logger, check the Logger and LogHTTPRequest handler
func (router *Router) logRequest(r *http.Request, succ bool, statusCode int, forwardType string, originalHostname string, upstreamHostname string) {
func (router *Router) logRequest(r *http.Request, succ bool, statusCode int, forwardType string, originalHostname string, upstreamHostname string, endpoint *ProxyEndpoint) {
if endpoint != nil && endpoint.DisableLogging {
// Notes: endpoint can be nil if the request has been handled before a host name can be resolved
// e.g. Redirection matching rule
// in that case we will log it by default and will not enter this routine
return
}
if router.Option.StatisticCollector != nil {
go func() {
requestInfo := statistic.RequestInfo{

View File

@@ -51,7 +51,7 @@ func (t *RequestCountPerIpTable) Clear() {
func (h *ProxyHandler) handleRateLimitRouting(w http.ResponseWriter, r *http.Request, pe *ProxyEndpoint) error {
err := h.Parent.handleRateLimit(w, r, pe)
if err != nil {
h.Parent.logRequest(r, false, 429, "ratelimit", r.URL.Hostname(), "")
h.Parent.logRequest(r, false, 429, "ratelimit", r.URL.Hostname(), "", pe)
}
return err
}

View File

@@ -208,6 +208,7 @@ type ProxyEndpoint struct {
//Uptime Monitor
DisableUptimeMonitor bool //Disable uptime monitor for this endpoint
DisableLogging bool //Disable logging of reverse proxy requests
// Chunked Transfer Encoding
DisableChunkedTransferEncoding bool //Disable chunked transfer encoding for this endpoint

View File

@@ -244,6 +244,9 @@ func ReverseProxyHandleAddEndpoint(w http.ResponseWriter, r *http.Request) {
enableUtm = true
}
// Disable logging?
disableLog, _ := utils.PostBool(r, "disableLog")
useBypassGlobalTLS := bypassGlobalTLS == "true"
//Enable TLS validation?
@@ -416,6 +419,7 @@ func ReverseProxyHandleAddEndpoint(w http.ResponseWriter, r *http.Request) {
Tags: tags,
DisableUptimeMonitor: !enableUtm,
DisableLogging: disableLog,
}
preparedEndpoint, err := dynamicProxyRouter.PrepareProxyRoute(&thisProxyEndpoint)
@@ -570,6 +574,9 @@ func ReverseProxyHandleEditEndpoint(w http.ResponseWriter, r *http.Request) {
// Disable chunked Encoding
disableChunkedEncoding, _ := utils.PostBool(r, "dChunkedEnc")
// Disable logging
disableLogging, _ := utils.PostBool(r, "dLogging")
//Load the previous basic auth credentials from current proxy rules
targetProxyEntry, err := dynamicProxyRouter.LoadProxy(rootNameOrMatchingDomain)
if err != nil {
@@ -611,6 +618,7 @@ func ReverseProxyHandleEditEndpoint(w http.ResponseWriter, r *http.Request) {
newProxyEndpoint.UseStickySession = useStickySession
newProxyEndpoint.DisableUptimeMonitor = disbleUtm
newProxyEndpoint.DisableChunkedTransferEncoding = disableChunkedEncoding
newProxyEndpoint.DisableLogging = disableLogging
newProxyEndpoint.Tags = tags
//Prepare to replace the current routing rule

View File

@@ -284,6 +284,12 @@
<label>Allow plain HTTP access<br>
<small>Allow inbound connections without TLS/SSL</small></label>
</div>
<br>
<div class="ui checkbox" style="margin-top: 0.4em;">
<input type="checkbox" class="DisableLogging">
<label>Disable Requests Logging<br>
<small>Disable logging for all incoming requests for this hostname</small></label>
</div>
</div>
</div>
@@ -885,6 +891,7 @@
let rateLimit = $(editor).find(".RateLimit").val();
let bypassGlobalTLS = $(editor).find(".BypassGlobalTLS")[0].checked;
let disableChunkedTransferEncoding = $(editor).find(".DisableChunkedTransferEncoding")[0].checked;
let disableLogging = $(editor).find(".DisableLogging")[0].checked;
let tags = getTagsArrayFromEndpoint(uuid);
if (tags.length > 0){
tags = tags.join(",");
@@ -901,6 +908,7 @@
"authprovider" :authProviderType,
"rate" :requireRateLimit,
"dChunkedEnc": disableChunkedTransferEncoding,
"dLogging": disableLogging,
"ratenum" :rateLimit,
"tags": tags,
};
@@ -1238,6 +1246,12 @@
editor.find(".BypassGlobalTLS").on("change", function() {
saveProxyInlineEdit(uuid);
});
editor.find(".DisableLogging").off('change');
editor.find(".DisableLogging").prop("checked", subd.DisableLogging);
editor.find(".DisableLogging").on("change", function() {
saveProxyInlineEdit(uuid);
});
//Bind the edit button
editor.find(".downstream_primary_hostname_edit_btn").off("click").on("click", function(){

View File

@@ -63,13 +63,20 @@
<label>Sticky Session<br><small>Enable stick session on upstream load balancing</small></label>
</div>
</div>
<div class="field">
<div class="field">
<div class="ui checkbox">
<input type="checkbox" id="enableUtm" checked>
<label>Enable uptime monitor<br><small>Automatically check upstream status and switch to another if offline</small>
</label>
</div>
</div>
<div class="field">
<div class="ui checkbox">
<input type="checkbox" id="disableLog">
<label>Disable Requests Logging<br><small>Disable requests logging for this host, recommended for high traffic sites</small>
</label>
</div>
</div>
<div class="field">
<label>Tags</label>
<input type="text" id="proxyTags" placeholder="e.g. mediaserver, management">
@@ -268,6 +275,7 @@
let useStickySessionLB = $("#useStickySessionLB")[0].checked;
let tags = $("#proxyTags").val().trim();
let enableUtm = $("#enableUtm")[0].checked;
let disableLog = $("#disableLog")[0].checked;
if (rootname.trim() == ""){
$("#rootname").parent().addClass("error");
@@ -302,7 +310,8 @@
access: accessRuleToUse,
stickysess: useStickySessionLB,
tags: tags,
enableUtm: enableUtm,
enableUtm: enableUtm,
disableLog: disableLog,
},
success: function(data){
if (data.error != undefined){