Skip to content

Commit

Permalink
feat: agent logs
Browse files Browse the repository at this point in the history
User can now get agent logs inside the project with the agent logs command

Signed-off-by: Toma Puljak <[email protected]>
  • Loading branch information
Tpuljak committed Apr 25, 2024
1 parent 71e4d3b commit ed36f3c
Show file tree
Hide file tree
Showing 10 changed files with 155 additions and 9 deletions.
4 changes: 2 additions & 2 deletions internal/util/log_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import (
"time"
)

func ReadLog(ctx context.Context, logReader *io.Reader, follow bool, c chan []byte, errChan chan error) {
reader := bufio.NewReader(*logReader)
func ReadLog(ctx context.Context, logReader io.Reader, follow bool, c chan []byte, errChan chan error) {
reader := bufio.NewReader(logReader)

for {
select {
Expand Down
2 changes: 2 additions & 0 deletions pkg/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import (
)

func (a *Agent) Start() error {
a.initLogs()

log.Info("Starting Daytona Agent")

a.startTime = time.Now()
Expand Down
21 changes: 18 additions & 3 deletions pkg/agent/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package config
import (
"errors"
"os"
"strings"

"github.com/go-playground/validator/v10"
"github.com/kelseyhightower/envconfig"
Expand All @@ -20,9 +21,10 @@ type DaytonaServerConfig struct {
}

type Config struct {
ProjectDir string `envconfig:"DAYTONA_WS_DIR"`
ProjectName string `envconfig:"DAYTONA_WS_PROJECT_NAME"`
WorkspaceId string `envconfig:"DAYTONA_WS_ID" validate:"required"`
ProjectDir string `envconfig:"DAYTONA_WS_DIR"`
ProjectName string `envconfig:"DAYTONA_WS_PROJECT_NAME"`
WorkspaceId string `envconfig:"DAYTONA_WS_ID" validate:"required"`
LogFilePath *string `envconfig:"DAYTONA_AGENT_LOG_FILE_PATH"`
Server DaytonaServerConfig
Mode Mode
}
Expand Down Expand Up @@ -69,5 +71,18 @@ func GetConfig(mode Mode) (*Config, error) {
}
}

config.LogFilePath = GetLogFilePath()

return config, nil
}

func GetLogFilePath() *string {
logFilePath, ok := os.LookupEnv("DAYTONA_AGENT_LOG_FILE_PATH")
if !ok {
return nil
}

logFilePath = strings.Replace(logFilePath, "$HOME", os.Getenv("HOME"), 1)

return &logFilePath
}
7 changes: 6 additions & 1 deletion pkg/agent/git/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package git

import (
"bytes"
"io"
"os"

"github.com/daytonaio/daytona/pkg/serverapiclient"
Expand All @@ -17,16 +18,20 @@ import (
type Service struct {
ProjectDir string
GitConfigFileName string
LogWriter io.Writer
}

func (s *Service) CloneRepository(project *serverapiclient.Project, authToken *string) error {
cloneOptions := &git.CloneOptions{
URL: *project.Repository.Url,
Progress: os.Stdout,
SingleBranch: true,
InsecureSkipTLS: true,
}

if s.LogWriter != nil {
cloneOptions.Progress = s.LogWriter
}

if authToken != nil {
cloneOptions.Auth = &http.BasicAuth{
Username: "daytona",
Expand Down
39 changes: 39 additions & 0 deletions pkg/agent/log.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package agent

import (
"io"

log "github.com/sirupsen/logrus"
)

type logFormatter struct {
textFormatter *log.TextFormatter
agentLogWriter io.Writer
}

func (f *logFormatter) Format(entry *log.Entry) ([]byte, error) {
formatted, err := f.textFormatter.Format(entry)
if err != nil {
return nil, err
}

if f.agentLogWriter != nil {
_, err = f.agentLogWriter.Write(formatted)
if err != nil {
return nil, err
}
}

return formatted, nil
}

func (s *Agent) initLogs() {
logFormatter := &logFormatter{
textFormatter: &log.TextFormatter{
ForceColors: true,
},
agentLogWriter: s.LogWriter,
}

log.SetFormatter(logFormatter)
}
2 changes: 2 additions & 0 deletions pkg/agent/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package agent

import (
"io"
"time"

"github.com/daytonaio/daytona/pkg/agent/config"
Expand All @@ -29,5 +30,6 @@ type Agent struct {
Git GitService
Ssh SshServer
Tailscale TailscaleServer
LogWriter io.Writer
startTime time.Time
}
6 changes: 3 additions & 3 deletions pkg/api/controllers/log/websocket.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func writeToWs(ws *websocket.Conn, c chan []byte, errChan chan error) {
}
}

func readLog(ginCtx *gin.Context, logReader *io.Reader) {
func readLog(ginCtx *gin.Context, logReader io.Reader) {
followQuery := ginCtx.Query("follow")
follow := followQuery == "true"

Expand Down Expand Up @@ -92,7 +92,7 @@ func ReadServerLog(ginCtx *gin.Context) {
return
}

readLog(ginCtx, &reader)
readLog(ginCtx, reader)
}

func ReadWorkspaceLog(ginCtx *gin.Context) {
Expand All @@ -106,5 +106,5 @@ func ReadWorkspaceLog(ginCtx *gin.Context) {
return
}

readLog(ginCtx, &wsLogReader)
readLog(ginCtx, wsLogReader)
}
20 changes: 20 additions & 0 deletions pkg/cmd/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package agent

import (
"io"
"os"
"path"

Expand All @@ -26,6 +27,10 @@ var AgentCmd = &cobra.Command{
Short: "Start the agent process",
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
if log.GetLevel() < log.InfoLevel {
log.SetLevel(log.InfoLevel)
}

agentMode := config.ModeProject

if hostModeFlag {
Expand All @@ -37,9 +42,22 @@ var AgentCmd = &cobra.Command{
log.Fatal(err)
}

gitLogWriter := io.MultiWriter(os.Stdout)
var agentLogWriter io.Writer
if config.LogFilePath != nil {
logFile, err := os.OpenFile(*config.LogFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
log.Fatal(err)
}
defer logFile.Close()
gitLogWriter = io.MultiWriter(os.Stdout, logFile)
agentLogWriter = logFile
}

git := &git.Service{
ProjectDir: config.ProjectDir,
GitConfigFileName: path.Join(os.Getenv("HOME"), ".gitconfig"),
LogWriter: gitLogWriter,
}

sshServer := &ssh.Server{
Expand All @@ -62,6 +80,7 @@ var AgentCmd = &cobra.Command{
Git: git,
Ssh: sshServer,
Tailscale: tailscaleServer,
LogWriter: agentLogWriter,
}

err = agent.Start()
Expand All @@ -73,4 +92,5 @@ var AgentCmd = &cobra.Command{

func init() {
AgentCmd.Flags().BoolVar(&hostModeFlag, "host", false, "Run the agent in host mode")
AgentCmd.AddCommand(logsCmd)
}
61 changes: 61 additions & 0 deletions pkg/cmd/agent/logs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright 2024 Daytona Platforms Inc.
// SPDX-License-Identifier: Apache-2.0

package agent

import (
"context"
"fmt"
"io"
"os"

"github.com/daytonaio/daytona/internal/util"
"github.com/daytonaio/daytona/pkg/agent/config"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)

var followFlag bool

var logsCmd = &cobra.Command{
Use: "logs",
Short: "Output Daytona Agent logs",
Run: func(cmd *cobra.Command, args []string) {
logFilePath := config.GetLogFilePath()

if logFilePath == nil {
log.Fatal("Log file path not set")
}

file, err := os.Open(*logFilePath)
if err != nil {
log.Fatal(err)
}
defer file.Close()

msgChan := make(chan []byte)
errChan := make(chan error)

go util.ReadLog(context.Background(), file, followFlag, msgChan, errChan)

for {
select {
case <-context.Background().Done():
return
case err := <-errChan:
if err != nil {
if err != io.EOF {
log.Fatal(err)
}
return
}
case msg := <-msgChan:
fmt.Println(string(msg))
}
}
},
}

func init() {
logsCmd.Flags().BoolVarP(&followFlag, "follow", "f", false, "Follow logs")
}
2 changes: 2 additions & 0 deletions pkg/workspace/workspace.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ func GetProjectEnvVars(project *Project, apiUrl, serverUrl string) map[string]st
"DAYTONA_SERVER_VERSION": internal.Version,
"DAYTONA_SERVER_URL": serverUrl,
"DAYTONA_SERVER_API_URL": apiUrl,
// $HOME will be replaced at runtime
"DAYTONA_AGENT_LOG_FILE_PATH": "$HOME/.daytona-agent.log",
}

return envVars
Expand Down

0 comments on commit ed36f3c

Please sign in to comment.