Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions docs/docs/telemetry.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,20 @@ When telemetry is active, we collect the following data. It is stored in the `te
| ActiveMinutes | The number of minutes that the user has actively used Waveterm on a given day. This requires the terminal window to be in focus while the user is actively interacting with it. |
| FgMinutes | The number of minutes that Waveterm has been in the foreground on a given day. This requires the terminal window to be in focus regardless of user interaction. |
| OpenMinutes | The number of minutes that Waveterm has been open on a given day. This only requires that the terminal is open, even if the window is out of focus. |
| NumBlocks | The number of existing blocks open on a given day |
| NumTabs | The number of existing tabs open on a given day. |
| NewTab | The number of new tabs created on a given day |
| NumWindows | The number of existing windows open on a give day. |
| NewTab | The number of new tabs opened on a given day. |
| NumStartup | The number of times waveterm has been started on a given day. |
| NumShutdown | The number of times waveterm has been shut down on a given day. |
| SetTabTheme | The number of times the tab theme is changed from the context menu |
| NumMagnify | The number of times any block is magnified |
| NumSSHConn | The number of distinct SSH connections that have been made to distinct hosts |
| NumWSLConns | The number of distinct WSL connections that have been made to distinct distros |
| Renderers | The number of new block views of each type are open on a given day. |
| WshCmds | The number of wsh commands of each type run on a given day |
| Conn | The number of successful remote connections made (and errors) on a given day |

## Associated Data

Expand All @@ -67,6 +76,7 @@ In addition to the telemetry data collected, the following is also reported. It
| ClientArch | This includes the user's operating system (e.g. linux or darwin) and architecture (e.g. x86_64 or arm64). It does not include data for any Connections at this time. |
| BuildTime | This serves as a more accurate version number that keeps track of when we built the version. It has no bearing on when that version was installed by you. |
| OSRelease | This lists the version of the operating system the user has installed. |
| Displays | Display resolutions (added in v0.9.3 to help us understand what screen resolutions to optimize for) |

## Telemetry Metadata

Expand Down
39 changes: 31 additions & 8 deletions emain/emain.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0

import { RpcApi } from "@/app/store/wshclientapi";
import * as electron from "electron";
import { FastAverageColor } from "fast-average-color";
import fs from "fs";
Expand All @@ -14,7 +15,6 @@ import winston from "winston";
import * as services from "../frontend/app/store/services";
import { initElectronWshrpc, shutdownWshrpc } from "../frontend/app/store/wshrpcutil";
import { getWebServerEndpoint } from "../frontend/util/endpoints";
import { fetch } from "../frontend/util/fetchutil";
import * as keyutil from "../frontend/util/keyutil";
import { fireAndForget } from "../frontend/util/util";
import { AuthKey, configureAuthKeyRequestInjection } from "./authkey";
Expand Down Expand Up @@ -518,16 +518,39 @@ electron.ipcMain.on("contextmenu-show", (event, menuDefArr?: ElectronContextMenu
event.returnValue = true;
});

// we try to set the primary display as index [0]
function getActivityDisplays(): ActivityDisplayType[] {
const displays = electron.screen.getAllDisplays();
const primaryDisplay = electron.screen.getPrimaryDisplay();
const rtn: ActivityDisplayType[] = [];
for (const display of displays) {
const adt = {
width: display.size.width,
height: display.size.height,
dpr: display.scaleFactor,
internal: display.internal,
};
if (display.id === primaryDisplay?.id) {
rtn.unshift(adt);
} else {
rtn.push(adt);
}
}
return rtn;
}

async function logActiveState() {
const astate = getActivityState();
const activeState = { fg: astate.wasInFg, active: astate.wasActive, open: true };
const url = new URL(getWebServerEndpoint() + "/wave/log-active-state");
const activity: ActivityUpdate = { openminutes: 1 };
if (astate.wasInFg) {
activity.fgminutes = 1;
}
if (astate.wasActive) {
activity.activeminutes = 1;
}
activity.displays = getActivityDisplays();
try {
const resp = await fetch(url, { method: "post", body: JSON.stringify(activeState) });
if (!resp.ok) {
console.log("error logging active state", resp.status, resp.statusText);
return;
}
RpcApi.ActivityCommand(ElectronWshClient, activity, { noresponse: true });
} catch (e) {
console.log("error logging active state", e);
} finally {
Expand Down
9 changes: 9 additions & 0 deletions frontend/types/gotypes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@

declare global {

// telemetry.ActivityDisplayType
type ActivityDisplayType = {
width: number;
height: number;
dpr: number;
internal?: boolean;
};

// telemetry.ActivityUpdate
type ActivityUpdate = {
fgminutes?: number;
Expand All @@ -21,6 +29,7 @@ declare global {
shutdown?: number;
settabtheme?: number;
buildtime?: string;
displays?: ActivityDisplayType[];
renderers?: {[key: string]: number};
wshcmds?: {[key: string]: number};
conn?: {[key: string]: number};
Expand Down
86 changes: 43 additions & 43 deletions pkg/telemetry/telemetry.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,36 +18,32 @@ import (

const MaxTzNameLen = 50

// "terminal" should not be in this list
var allowedRenderers = map[string]bool{
"markdown": true,
"code": true,
"openai": true,
"csv": true,
"image": true,
"pdf": true,
"media": true,
"mustache": true,
type ActivityDisplayType struct {
Width int `json:"width"`
Height int `json:"height"`
DPR float64 `json:"dpr"`
Internal bool `json:"internal,omitempty"`
}

type ActivityUpdate struct {
FgMinutes int `json:"fgminutes,omitempty"`
ActiveMinutes int `json:"activeminutes,omitempty"`
OpenMinutes int `json:"openminutes,omitempty"`
NumTabs int `json:"numtabs,omitempty"`
NewTab int `json:"newtab,omitempty"`
NumBlocks int `json:"numblocks,omitempty"`
NumWindows int `json:"numwindows,omitempty"`
NumSSHConn int `json:"numsshconn,omitempty"`
NumWSLConn int `json:"numwslconn,omitempty"`
NumMagnify int `json:"nummagnify,omitempty"`
Startup int `json:"startup,omitempty"`
Shutdown int `json:"shutdown,omitempty"`
SetTabTheme int `json:"settabtheme,omitempty"`
BuildTime string `json:"buildtime,omitempty"`
Renderers map[string]int `json:"renderers,omitempty"`
WshCmds map[string]int `json:"wshcmds,omitempty"`
Conn map[string]int `json:"conn,omitempty"`
FgMinutes int `json:"fgminutes,omitempty"`
ActiveMinutes int `json:"activeminutes,omitempty"`
OpenMinutes int `json:"openminutes,omitempty"`
NumTabs int `json:"numtabs,omitempty"`
NewTab int `json:"newtab,omitempty"`
NumBlocks int `json:"numblocks,omitempty"`
NumWindows int `json:"numwindows,omitempty"`
NumSSHConn int `json:"numsshconn,omitempty"`
NumWSLConn int `json:"numwslconn,omitempty"`
NumMagnify int `json:"nummagnify,omitempty"`
Startup int `json:"startup,omitempty"`
Shutdown int `json:"shutdown,omitempty"`
SetTabTheme int `json:"settabtheme,omitempty"`
BuildTime string `json:"buildtime,omitempty"`
Displays []ActivityDisplayType `json:"displays,omitempty"`
Renderers map[string]int `json:"renderers,omitempty"`
WshCmds map[string]int `json:"wshcmds,omitempty"`
Conn map[string]int `json:"conn,omitempty"`
}

type ActivityType struct {
Expand All @@ -63,22 +59,23 @@ type ActivityType struct {
}

type TelemetryData struct {
ActiveMinutes int `json:"activeminutes"`
FgMinutes int `json:"fgminutes"`
OpenMinutes int `json:"openminutes"`
NumTabs int `json:"numtabs"`
NumBlocks int `json:"numblocks,omitempty"`
NumWindows int `json:"numwindows,omitempty"`
NumSSHConn int `json:"numsshconn,omitempty"`
NumWSLConn int `json:"numwslconn,omitempty"`
NumMagnify int `json:"nummagnify,omitempty"`
NewTab int `json:"newtab"`
NumStartup int `json:"numstartup,omitempty"`
NumShutdown int `json:"numshutdown,omitempty"`
SetTabTheme int `json:"settabtheme,omitempty"`
Renderers map[string]int `json:"renderers,omitempty"`
WshCmds map[string]int `json:"wshcmds,omitempty"`
Conn map[string]int `json:"conn,omitempty"`
ActiveMinutes int `json:"activeminutes"`
FgMinutes int `json:"fgminutes"`
OpenMinutes int `json:"openminutes"`
NumTabs int `json:"numtabs"`
NumBlocks int `json:"numblocks,omitempty"`
NumWindows int `json:"numwindows,omitempty"`
NumSSHConn int `json:"numsshconn,omitempty"`
NumWSLConn int `json:"numwslconn,omitempty"`
NumMagnify int `json:"nummagnify,omitempty"`
NewTab int `json:"newtab"`
NumStartup int `json:"numstartup,omitempty"`
NumShutdown int `json:"numshutdown,omitempty"`
SetTabTheme int `json:"settabtheme,omitempty"`
Displays []ActivityDisplayType `json:"displays,omitempty"`
Renderers map[string]int `json:"renderers,omitempty"`
WshCmds map[string]int `json:"wshcmds,omitempty"`
Conn map[string]int `json:"conn,omitempty"`
}

func (tdata TelemetryData) Value() (driver.Value, error) {
Expand Down Expand Up @@ -180,6 +177,9 @@ func UpdateActivity(ctx context.Context, update ActivityUpdate) error {
tdata.Conn[key] += val
}
}
if len(update.Displays) > 0 {
tdata.Displays = update.Displays
}
query = `UPDATE db_activity
SET tdata = ?,
clientversion = ?,
Expand Down
32 changes: 0 additions & 32 deletions pkg/web/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,11 @@ import (
"github.com/wavetermdev/waveterm/pkg/docsite"
"github.com/wavetermdev/waveterm/pkg/filestore"
"github.com/wavetermdev/waveterm/pkg/service"
"github.com/wavetermdev/waveterm/pkg/telemetry"
"github.com/wavetermdev/waveterm/pkg/wavebase"
"github.com/wavetermdev/waveterm/pkg/waveobj"
"github.com/wavetermdev/waveterm/pkg/wshrpc"
"github.com/wavetermdev/waveterm/pkg/wshrpc/wshclient"
"github.com/wavetermdev/waveterm/pkg/wshrpc/wshserver"
"github.com/wavetermdev/waveterm/pkg/wshutil"
"github.com/wavetermdev/waveterm/pkg/wstore"
)

type WebFnType = func(http.ResponseWriter, *http.Request)
Expand Down Expand Up @@ -358,34 +355,6 @@ type ClientActiveState struct {
Open bool `json:"open"`
}

// params: fg, active, open
func handleLogActiveState(w http.ResponseWriter, r *http.Request) {
decoder := json.NewDecoder(r.Body)
var activeState ClientActiveState
err := decoder.Decode(&activeState)
if err != nil {
WriteJsonError(w, fmt.Errorf("error decoding json: %v", err))
return
}
activity := telemetry.ActivityUpdate{}
if activeState.Fg {
activity.FgMinutes = 1
}
if activeState.Active {
activity.ActiveMinutes = 1
}
if activeState.Open {
activity.OpenMinutes = 1
}
activity.NumTabs, _ = wstore.DBGetCount[*waveobj.Tab](r.Context())
err = telemetry.UpdateActivity(r.Context(), activity)
if err != nil {
WriteJsonError(w, fmt.Errorf("error updating activity: %w", err))
return
}
WriteJsonSuccess(w, true)
}

func WebFnWrap(opts WebFnOpts, fn WebFnType) WebFnType {
return func(w http.ResponseWriter, r *http.Request) {
defer func() {
Expand Down Expand Up @@ -450,7 +419,6 @@ func RunWebServer(listener net.Listener) {
gr.HandleFunc("/wave/stream-file", WebFnWrap(WebFnOpts{AllowCaching: true}, handleStreamFile))
gr.HandleFunc("/wave/file", WebFnWrap(WebFnOpts{AllowCaching: false}, handleWaveFile))
gr.HandleFunc("/wave/service", WebFnWrap(WebFnOpts{JsonErrors: true}, handleService))
gr.HandleFunc("/wave/log-active-state", WebFnWrap(WebFnOpts{JsonErrors: true}, handleLogActiveState))
gr.HandleFunc("/vdom/{uuid}/{path:.*}", WebFnWrap(WebFnOpts{AllowCaching: true}, handleVDom))
gr.PathPrefix(docsitePrefix).Handler(http.StripPrefix(docsitePrefix, docsite.GetDocsiteHandler()))
handler := http.TimeoutHandler(gr, HttpTimeoutDuration, "Timeout")
Expand Down