waveterm/pkg/blocklogger/blocklogger.go
Mike Sawka ba5f929b3f
conn updates 3 (#1711)
lots of misc connection refactoring / fixes:

* adds blocklogger as a way to writing logging information from the backend directly to the a terminal block
* use blocklogger in conncontroller
* use blocklogger in sshclient
* fix remote name in password prompt
* use sh -c to get around shell weirdness
* remove cmd.exe special cases
* use GetWatcher().GetFullConfig() rather than re-reading the config file
* change order of things we do when establishing a connection.  ask for wsh up front.  then do domain socket, then connserver
* reduce number of sessions required in the common case when wsh is already installed.  running the connserver is now a "multi-command" which checks if it is installed, then asks for the version
* send jwt token over stdin instead of in initial command string
* fix focus bug for frontend conn modal
* track more information in connstatus
* simplify wshinstall function
* add nowshreason
* other misc cleanup
2025-01-10 14:09:32 -08:00

93 lines
2.2 KiB
Go

// Copyright 2025, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
package blocklogger
import (
"context"
"encoding/base64"
"fmt"
"log"
"strings"
"github.com/wavetermdev/waveterm/pkg/wshrpc"
"github.com/wavetermdev/waveterm/pkg/wshrpc/wshclient"
)
// Buffer size for the output channel
const outputBufferSize = 1000
var outputChan chan wshrpc.CommandControllerAppendOutputData
func InitBlockLogger() {
outputChan = make(chan wshrpc.CommandControllerAppendOutputData, outputBufferSize)
// Start the output runner
go outputRunner()
}
func outputRunner() {
defer log.Printf("blocklogger: outputRunner exiting")
client := wshclient.GetBareRpcClient()
for data := range outputChan {
// Process each output request synchronously, waiting for response
wshclient.ControllerAppendOutputCommand(client, data, nil)
}
}
type logBlockIdContextKeyType struct{}
var logBlockIdContextKey = logBlockIdContextKeyType{}
type logBlockIdData struct {
BlockId string
Verbose bool
}
func ContextWithLogBlockId(ctx context.Context, blockId string, verbose bool) context.Context {
return context.WithValue(ctx, logBlockIdContextKey, &logBlockIdData{BlockId: blockId, Verbose: verbose})
}
func getLogBlockData(ctx context.Context) *logBlockIdData {
if ctx == nil {
return nil
}
dataPtr := ctx.Value(logBlockIdContextKey)
if dataPtr == nil {
return nil
}
return dataPtr.(*logBlockIdData)
}
func queueLogData(data wshrpc.CommandControllerAppendOutputData) {
select {
case outputChan <- data:
default:
}
}
func writeLogf(blockId string, format string, args []any) {
logStr := fmt.Sprintf(format, args...)
logStr = strings.ReplaceAll(logStr, "\n", "\r\n")
data := wshrpc.CommandControllerAppendOutputData{
BlockId: blockId,
Data64: base64.StdEncoding.EncodeToString([]byte(logStr)),
}
queueLogData(data)
}
func Infof(ctx context.Context, format string, args ...any) {
logData := getLogBlockData(ctx)
if logData == nil {
return
}
writeLogf(logData.BlockId, format, args)
}
func Debugf(ctx context.Context, format string, args ...interface{}) {
logData := getLogBlockData(ctx)
if logData == nil || !logData.Verbose {
return
}
writeLogf(logData.BlockId, format, args)
}