client/web: add metric logging logic to the web client (#10434)
Add metric logging logic for the web client frontend. This is an initial pass of adding the base logic, plus a single point where it is used for validation that the logging is working correctly. More metric logging calls will follow in subsquent PRs. Updates https://github.com/tailscale/tailscale/issues/10261 Signed-off-by: Mario Minardi <mario@tailscale.com>
This commit is contained in:
parent
9c4b73d77d
commit
6b083a8ddf
|
@ -77,3 +77,30 @@ export function setSynoToken(token?: string) {
|
|||
export function setUnraidCsrfToken(token?: string) {
|
||||
unraidCsrfToken = token
|
||||
}
|
||||
|
||||
// incrementMetric hits the client metrics local API endpoint to
|
||||
// increment the given counter metric by one.
|
||||
export function incrementMetric(metricName: MetricName) {
|
||||
const postData : MetricsPOSTData[] = [{
|
||||
Name: metricName,
|
||||
Type: "counter",
|
||||
Value: 1
|
||||
}]
|
||||
|
||||
apiFetch("/local/v0/upload-client-metrics", "POST", postData)
|
||||
.catch((error) => {
|
||||
console.error(error)
|
||||
})
|
||||
}
|
||||
|
||||
type MetricsPOSTData = {
|
||||
Name: MetricName
|
||||
Type: MetricType
|
||||
Value: number
|
||||
}
|
||||
|
||||
type MetricType = "counter" | "gauge"
|
||||
|
||||
export type MetricName =
|
||||
| "web_client_advertise_exitnode_enable"
|
||||
| "web_client_advertise_exitnode_disable"
|
||||
|
|
|
@ -6,6 +6,7 @@ import { apiFetch, setUnraidCsrfToken } from "src/api"
|
|||
import { ExitNode, noExitNode, runAsExitNode } from "src/hooks/exit-nodes"
|
||||
import { VersionInfo } from "src/hooks/self-update"
|
||||
import { assertNever } from "src/util"
|
||||
import { incrementMetric, MetricName } from "src/api"
|
||||
|
||||
export type NodeData = {
|
||||
Profile: UserProfile
|
||||
|
@ -173,16 +174,25 @@ export default function useNodeData() {
|
|||
setIsPosting(false)
|
||||
refreshData() // refresh data after POST finishes
|
||||
}
|
||||
const updateMetrics = () => {
|
||||
// only update metrics if values have changed
|
||||
if (data?.AdvertisingExitNode !== d.AdvertiseExitNode) {
|
||||
incrementMetric(d.AdvertiseExitNode ? "web_client_advertise_exitnode_enable" : "web_client_advertise_exitnode_disable")
|
||||
}
|
||||
}
|
||||
|
||||
return apiFetch("/routes", "POST", d)
|
||||
.then(onComplete)
|
||||
.then(() => {
|
||||
updateMetrics()
|
||||
onComplete()
|
||||
})
|
||||
.catch((err) => {
|
||||
onComplete()
|
||||
alert("Failed to update routes")
|
||||
throw err
|
||||
})
|
||||
},
|
||||
[setIsPosting, refreshData]
|
||||
[setIsPosting, refreshData, data?.AdvertisingExitNode]
|
||||
)
|
||||
|
||||
useEffect(
|
||||
|
|
|
@ -759,12 +759,6 @@ func (s *Server) servePostRoutes(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
oldPrefs, err := s.lc.GetPrefs(r.Context())
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Calculate routes.
|
||||
routesStr := strings.Join(data.AdvertiseRoutes, ",")
|
||||
routes, err := netutil.CalcAdvertiseRoutes(routesStr, data.AdvertiseExitNode)
|
||||
|
@ -797,15 +791,6 @@ func (s *Server) servePostRoutes(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
// Report metrics.
|
||||
if data.AdvertiseExitNode != hasExitNodeRoute(oldPrefs.AdvertiseRoutes) {
|
||||
if data.AdvertiseExitNode {
|
||||
s.lc.IncrementCounter(r.Context(), "web_client_advertise_exitnode_enable", 1)
|
||||
} else {
|
||||
s.lc.IncrementCounter(r.Context(), "web_client_advertise_exitnode_disable", 1)
|
||||
}
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
|
@ -979,6 +964,7 @@ var localapiAllowlist = []string{
|
|||
"/v0/update/check",
|
||||
"/v0/update/install",
|
||||
"/v0/update/progress",
|
||||
"/v0/upload-client-metrics",
|
||||
}
|
||||
|
||||
// csrfKey returns a key that can be used for CSRF protection.
|
||||
|
|
Loading…
Reference in New Issue