Skip to content

Commit 0d20cdb

Browse files
author
mirkobrombin
committed
feat: enhance NodeJSPlugin with dedicated logging for Node.JS
1 parent d5d1f12 commit 0d20cdb

File tree

1 file changed

+62
-63
lines changed

1 file changed

+62
-63
lines changed

plugins/nodejs.go

Lines changed: 62 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"sync"
1212

1313
"github.com/mirkobrombin/goup/internal/config"
14+
"github.com/mirkobrombin/goup/internal/logger"
1415
"github.com/mirkobrombin/goup/internal/server/middleware"
1516
log "github.com/sirupsen/logrus"
1617
)
@@ -19,6 +20,7 @@ import (
1920
type NodeJSPlugin struct {
2021
mu sync.Mutex
2122
process *os.Process
23+
logger *log.Logger
2224
}
2325

2426
// Name returns the name of the plugin.
@@ -32,8 +34,17 @@ func (p *NodeJSPlugin) Init(mwManager *middleware.MiddlewareManager) error {
3234
}
3335

3436
// InitForSite initializes the plugin for a specific site.
35-
func (p *NodeJSPlugin) InitForSite(mwManager *middleware.MiddlewareManager, logger *log.Logger, conf config.SiteConfig) error {
36-
mwManager.Use(p.nodeMiddleware(logger, conf))
37+
func (p *NodeJSPlugin) InitForSite(mwManager *middleware.MiddlewareManager, baseLogger *log.Logger, conf config.SiteConfig) error {
38+
// Create a dedicated logger for this plugin/site.
39+
pluginLogger, err := logger.NewPluginLogger(conf.Domain, p.Name())
40+
if err != nil {
41+
baseLogger.Errorf("Failed to create NodeJSPlugin logger: %v", err)
42+
return err
43+
}
44+
p.logger = pluginLogger
45+
46+
// Add the Node.js middleware to intercept matching requests.
47+
mwManager.Use(p.nodeMiddleware(pluginLogger, conf))
3748
return nil
3849
}
3950

@@ -49,18 +60,21 @@ type NodeJSPluginConfig struct {
4960
ProxyPaths []string `json:"proxy_paths"`
5061
}
5162

52-
// nodeMiddleware intercepts requests and forwards API calls to Node.js.
53-
func (p *NodeJSPlugin) nodeMiddleware(logger *log.Logger, conf config.SiteConfig) middleware.MiddlewareFunc {
63+
// nodeMiddleware intercepts requests and forwards them to Node.js if they
64+
// match ProxyPaths.
65+
func (p *NodeJSPlugin) nodeMiddleware(baseLogger *log.Logger, conf config.SiteConfig) middleware.MiddlewareFunc {
5466
return func(next http.Handler) http.Handler {
5567
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
56-
// Retrieve site-specific plugin configuration.
68+
69+
// Retrieve plugin config for the current site.
5770
pluginConfigRaw, ok := conf.PluginConfigs[p.Name()]
5871
if !ok {
72+
// If there's no configuration for this plugin, just move on.
5973
next.ServeHTTP(w, r)
6074
return
6175
}
6276

63-
// Parse configuration.
77+
// Map the raw config to a strong type.
6478
pluginConfig := NodeJSPluginConfig{}
6579
if rawMap, ok := pluginConfigRaw.(map[string]interface{}); ok {
6680
if enable, ok := rawMap["enable"].(bool); ok {
@@ -93,45 +107,45 @@ func (p *NodeJSPlugin) nodeMiddleware(logger *log.Logger, conf config.SiteConfig
93107
}
94108
}
95109

110+
// If disabled, do nothing.
96111
if !pluginConfig.Enable {
97-
logger.Infof("NodeJS Plugin is disabled for host: %s", r.Host)
112+
baseLogger.Infof("NodeJS Plugin disabled for host: %s", r.Host)
98113
next.ServeHTTP(w, r)
99114
return
100115
}
101116

102-
// Start Node.js if it is not already running.
103-
p.ensureNodeServerRunning(pluginConfig, logger)
117+
// Ensure Node.js is running.
118+
p.ensureNodeServerRunning(pluginConfig)
104119

105-
// Check if the request should be forwarded to Node.js.
120+
// Check if the request path should be forwarded to Node.js.
106121
for _, proxyPath := range pluginConfig.ProxyPaths {
107122
if strings.HasPrefix(r.URL.Path, proxyPath) {
108-
p.proxyToNode(w, r, pluginConfig, logger)
123+
p.proxyToNode(w, r, pluginConfig)
109124
return
110125
}
111126
}
112127

113-
// If the request does not match a Node.js route, let GoUp handle static files.
128+
// If it doesn't match, serve static files as usual.
114129
next.ServeHTTP(w, r)
115130
})
116131
}
117132
}
118133

119134
// ensureNodeServerRunning starts Node.js if it is not already running.
120-
func (p *NodeJSPlugin) ensureNodeServerRunning(config NodeJSPluginConfig, logger *log.Logger) {
135+
func (p *NodeJSPlugin) ensureNodeServerRunning(config NodeJSPluginConfig) {
121136
p.mu.Lock()
122137
defer p.mu.Unlock()
123138

124139
// If the process is already running, do nothing.
125140
if p.process != nil {
126-
logger.Infof("Node.js server is already running (PID: %d)", p.process.Pid)
127141
return
128142
}
129143

130-
logger.Infof("Starting Node.js server...")
144+
p.logger.Infof("Starting Node.js server...")
131145

132146
// Install dependencies if required.
133147
if config.InstallDeps {
134-
p.installDependencies(config, logger)
148+
p.installDependencies(config)
135149
}
136150

137151
// Start the Node.js server.
@@ -144,35 +158,46 @@ func (p *NodeJSPlugin) ensureNodeServerRunning(config NodeJSPluginConfig, logger
144158

145159
cmd := exec.Command(nodePath, entryPath)
146160
cmd.Dir = config.RootDir
147-
cmd.Stdout = os.Stdout
148-
cmd.Stderr = os.Stderr
161+
162+
// Redirect the Node.js output to the plugin logger instead of stdout.
163+
cmd.Stdout = p.logger.Writer()
164+
cmd.Stderr = p.logger.Writer()
149165

150166
if err := cmd.Start(); err != nil {
151-
logger.Errorf("Failed to start Node.js server: %v", err)
167+
p.logger.Errorf("Failed to start Node.js server: %v", err)
152168
return
153169
}
154170

171+
// Store the process to avoid multiple starts.
155172
p.process = cmd.Process
156-
logger.Infof("Started Node.js server (PID: %d) on port %s", p.process.Pid, config.Port)
173+
174+
p.logger.Infof("Started Node.js server (PID: %d) on port %s", p.process.Pid, config.Port)
175+
176+
// Optionally, handle process exit to close the writers.
177+
go func() {
178+
err := cmd.Wait()
179+
p.logger.Infof("Node.js server exited (PID: %d), error=%v", p.process.Pid, err)
180+
// Close the logger writers to free resources.
181+
p.logger.Writer().Close()
182+
}()
157183
}
158184

159-
// proxyToNode forwards the original request to Node.js and returns the response.
160-
func (p *NodeJSPlugin) proxyToNode(w http.ResponseWriter, r *http.Request, config NodeJSPluginConfig, logger *log.Logger) {
161-
// Construct the URL for forwarding the request to Node.js.
185+
// proxyToNode forwards the original HTTP request to Node.js and sends back
186+
// the response.
187+
func (p *NodeJSPlugin) proxyToNode(w http.ResponseWriter, r *http.Request, config NodeJSPluginConfig) {
162188
nodeURL := fmt.Sprintf("http://localhost:%s%s", config.Port, r.URL.Path)
163189

164-
// Create a new HTTP request forwarding the original request data.
165190
bodyReader, err := io.ReadAll(r.Body)
166191
if err != nil {
167-
logger.Errorf("Failed to read request body: %v", err)
192+
p.logger.Errorf("Failed to read request body: %v", err)
168193
http.Error(w, "Failed to read request body", http.StatusInternalServerError)
169194
return
170195
}
171196
defer r.Body.Close()
172197

173198
req, err := http.NewRequest(r.Method, nodeURL, strings.NewReader(string(bodyReader)))
174199
if err != nil {
175-
logger.Errorf("Failed to create request for Node.js: %v", err)
200+
p.logger.Errorf("Failed to create request for Node.js: %v", err)
176201
http.Error(w, "Failed to create request", http.StatusInternalServerError)
177202
return
178203
}
@@ -187,13 +212,13 @@ func (p *NodeJSPlugin) proxyToNode(w http.ResponseWriter, r *http.Request, confi
187212
client := &http.Client{}
188213
resp, err := client.Do(req)
189214
if err != nil {
190-
logger.Errorf("Failed to connect to Node.js backend: %v", err)
215+
p.logger.Errorf("Failed to connect to Node.js backend: %v", err)
191216
http.Error(w, "Node.js backend unavailable", http.StatusBadGateway)
192217
return
193218
}
194219
defer resp.Body.Close()
195220

196-
// Copy response headers.
221+
// Forward response headers back to the client.
197222
for key, values := range resp.Header {
198223
for _, value := range values {
199224
w.Header().Add(key, value)
@@ -204,61 +229,35 @@ func (p *NodeJSPlugin) proxyToNode(w http.ResponseWriter, r *http.Request, confi
204229
w.WriteHeader(resp.StatusCode)
205230
body, err := io.ReadAll(resp.Body)
206231
if err != nil {
207-
logger.Errorf("Failed to read response body from Node.js: %v", err)
232+
p.logger.Errorf("Failed to read response body from Node.js: %v", err)
208233
http.Error(w, "Failed to read response from Node.js", http.StatusInternalServerError)
209234
return
210235
}
211236

212237
w.Write(body)
213238
}
214239

215-
// startNodeServer ensures the Node.js server is running.
216-
func (p *NodeJSPlugin) startNodeServer(config NodeJSPluginConfig, logger *log.Logger) {
217-
logger.Infof("Starting Node.js server...")
218-
p.mu.Lock()
219-
defer p.mu.Unlock()
220-
221-
// Install dependencies if needed.
222-
if config.InstallDeps {
223-
p.installDependencies(config, logger)
224-
}
225-
226-
// Start the Node.js server.
227-
entryPath := filepath.Join(config.RootDir, config.Entry)
228-
cmd := exec.Command(config.NodePath, entryPath)
229-
cmd.Dir = config.RootDir
230-
cmd.Stdout = os.Stdout
231-
cmd.Stderr = os.Stderr
232-
233-
if err := cmd.Start(); err != nil {
234-
logger.Errorf("Failed to start Node.js server: %v", err)
235-
return
236-
}
237-
238-
p.process = cmd.Process
239-
logger.Infof("Started Node.js server (PID: %d) on port %s", p.process.Pid, config.Port)
240-
}
241-
242240
// installDependencies installs dependencies using the configured package manager.
243-
func (p *NodeJSPlugin) installDependencies(config NodeJSPluginConfig, logger *log.Logger) {
241+
func (p *NodeJSPlugin) installDependencies(config NodeJSPluginConfig) {
244242
nodeModulesPath := filepath.Join(config.RootDir, "node_modules")
245243
if _, err := os.Stat(nodeModulesPath); os.IsNotExist(err) {
246-
logger.Infof("node_modules not found, installing dependencies in %s", config.RootDir)
244+
p.logger.Infof("node_modules not found, installing dependencies in %s", config.RootDir)
247245

248246
packageManager := config.PackageManager
249247
if packageManager == "" {
250248
packageManager = "npm"
251249
}
252250

253-
logger.Infof("Using package manager: %s", packageManager)
251+
p.logger.Infof("Using package manager: %s", packageManager)
254252
cmd := exec.Command(packageManager, "install")
255253
cmd.Dir = config.RootDir
256-
cmd.Stdout = os.Stdout
257-
cmd.Stderr = os.Stderr
254+
cmd.Stdout = p.logger.Writer()
255+
cmd.Stderr = p.logger.Writer()
256+
258257
if err := cmd.Run(); err != nil {
259-
logger.Errorf("Failed to install dependencies using %s: %v", packageManager, err)
258+
p.logger.Errorf("Failed to install dependencies using %s: %v", packageManager, err)
260259
} else {
261-
logger.Infof("Dependencies installed successfully using %s", packageManager)
260+
p.logger.Infof("Dependencies installed successfully using %s", packageManager)
262261
}
263262
}
264263
}

0 commit comments

Comments
 (0)