@@ -49,25 +49,102 @@ const productResources: Record<string, ResourceLink[]> = {
4949 ] ,
5050} ;
5151
52- // Where each product writes its logs, keyed by product value then platform
53- // value. Shown once both are known. Paths come from the Coder docs. Values are
54- // Markdown; a product/platform without an entry simply shows no hint.
55- const logLocations : Record < string , Partial < Record < string , string > > > = {
52+ // The log guide for a product/platform is one section per log source, split by
53+ // dividers, then a docs link. `default` covers platforms without a specific
54+ // entry. Paths and commands come from the Coder repo and docs.
55+ type LogSection = { title : string ; location : string ; command : string } ;
56+ type LogGuide = { sections : LogSection [ ] ; footer : string } ;
57+
58+ const architectureDocs =
59+ "https://coder.com/docs/admin/infrastructure/architecture" ;
60+ const coderFooter = `Learn about the difference between the Coder Server and Agent at ${ architectureDocs } ` ;
61+
62+ const agentSectionUnix : LogSection = {
63+ title : "Coder Workspace Agent/`coder agent`" ,
64+ location : "`/tmp/coder-agent.log` inside the workspace" ,
65+ command : "coder ssh <workspace> -- cat /tmp/coder-agent.log" ,
66+ } ;
67+
68+ const logGuides : Record < string , Partial < Record < string , LogGuide > > > = {
5669 coder : {
57- linux :
58- "Server: `journalctl -u coder` on a VM, or `kubectl logs deployment/coder -n <namespace>` on Kubernetes.\nWorkspace agent: `/tmp/coder-agent.log`." ,
59- macos : "Workspace agent: `/tmp/coder-agent.log`." ,
60- windows :
61- "Workspace agent logs live wherever your template writes them; check the template's startup script." ,
70+ linux : {
71+ sections : [
72+ {
73+ title : "Coder Server/`coderd`" ,
74+ location : "the systemd journal (`coderd` writes to standard output)" ,
75+ command :
76+ "sudo journalctl -u coder.service --no-pager\n# Docker: docker logs coder\n# Kubernetes: kubectl logs deployment/coder -n coder" ,
77+ } ,
78+ agentSectionUnix ,
79+ ] ,
80+ footer : coderFooter ,
81+ } ,
82+ macos : {
83+ sections : [
84+ {
85+ title : "Coder Server/`coderd`" ,
86+ location :
87+ "standard output (`coderd` has no default log file on macOS)" ,
88+ command :
89+ 'CODER_LOGGING_HUMAN="$HOME/coder.log" coder server\ncat "$HOME/coder.log"' ,
90+ } ,
91+ agentSectionUnix ,
92+ ] ,
93+ footer : coderFooter ,
94+ } ,
95+ windows : {
96+ sections : [
97+ {
98+ title : "Coder Server/`coderd`" ,
99+ location :
100+ "standard output (`coderd` has no default log file on Windows)" ,
101+ command :
102+ '$env:CODER_LOGGING_HUMAN="$HOME\\coder.log"; coder server\nGet-Content "$HOME\\coder.log"' ,
103+ } ,
104+ {
105+ title : "Coder Workspace Agent/`coder agent`" ,
106+ location :
107+ "the path your template sets (the azure-windows example uses `C:\\AzureData\\CoderAgent.log`)" ,
108+ command :
109+ 'coder ssh <workspace> -- powershell -Command "Get-Content C:\\AzureData\\CoderAgent.log"' ,
110+ } ,
111+ ] ,
112+ footer : coderFooter ,
113+ } ,
114+ default : {
115+ sections : [
116+ {
117+ title : "Coder Server/`coderd`" ,
118+ location :
119+ "standard output; capture it to a file with `CODER_LOGGING_HUMAN`" ,
120+ command : 'CODER_LOGGING_HUMAN="$HOME/coder.log" coder server' ,
121+ } ,
122+ agentSectionUnix ,
123+ ] ,
124+ footer : coderFooter ,
125+ } ,
62126 } ,
63127 "code-server" : {
64- linux :
65- "`~/.local/share/code-server/coder-logs/` (and `~/.vscode-server/data/logs/` for the VS Code server)." ,
66- macos :
67- "`~/.local/share/code-server/coder-logs/` (and `~/.vscode-server/data/logs/` for the VS Code server)." ,
128+ default : {
129+ sections : [
130+ {
131+ title : "code-server" ,
132+ location :
133+ "`/tmp/code-server.log` (the Coder code-server module default; code-server's own logs live under `~/.local/share/code-server/`)" ,
134+ command : "coder ssh <workspace> -- cat /tmp/code-server.log" ,
135+ } ,
136+ ] ,
137+ footer :
138+ "code-server is configured by the Coder code-server module: https://registry.coder.com/modules/coder/code-server" ,
139+ } ,
68140 } ,
69141} ;
70142
143+ const logGuideFor = ( product ?: string , platform ?: string ) => {
144+ const perProduct = product ? logGuides [ product ] : undefined ;
145+ return perProduct ?. [ platform ?? "" ] ?? perProduct ?. default ;
146+ } ;
147+
71148// The walkthrough asks one selector per field, in this order.
72149const steps = [
73150 {
@@ -135,6 +212,33 @@ async function lifecycleText(client: Client) {
135212 return `When your issue is resolved, use ${ close } to close it.\nUse ${ reopen } to reopen it if needed.` ;
136213}
137214
215+ // Renders the "where are my logs" container for the chosen product and
216+ // platform: one section per log source separated by dividers, then a docs link.
217+ // Returns undefined when there is no guide for the product.
218+ function logGuideComponent ( product ?: string , platform ?: string ) {
219+ const guide = logGuideFor ( product , platform ) ;
220+ if ( ! guide ) {
221+ return undefined ;
222+ }
223+
224+ const container = new ContainerBuilder ( ) . setAccentColor ( Colors . Blurple ) ;
225+
226+ guide . sections . forEach ( ( section , index ) => {
227+ if ( index > 0 ) {
228+ container . addSeparatorComponents ( new SeparatorBuilder ( ) ) ;
229+ }
230+ container . addTextDisplayComponents (
231+ text (
232+ `${ section . title } logs are located at ${ section . location } .\n\nYou can get them easily via:\n\`\`\`\n${ section . command } \n\`\`\`` ,
233+ ) ,
234+ ) ;
235+ } ) ;
236+
237+ return container
238+ . addSeparatorComponents ( new SeparatorBuilder ( ) )
239+ . addTextDisplayComponents ( text ( guide . footer ) ) ;
240+ }
241+
138242// Builds the walkthrough message from the answered values so far: an info
139243// container with a field row per answer, the current question and selector while
140244// steps remain, and the selected product's documentation buttons at the bottom.
@@ -189,17 +293,13 @@ async function buildMessage(
189293 ) ;
190294 }
191295
192- // The log locations depend on the platform, so hide them while that answer is
193- // being edited. When editing another field, show them above the question.
194- const logHint =
195- editIndex === 2 ? undefined : logLocations [ values [ 1 ] ] ?. [ values [ 2 ] ] ;
196- const logComponent = logHint
197- ? new ContainerBuilder ( )
198- . setAccentColor ( Colors . Blurple )
199- . addTextDisplayComponents (
200- text ( `**Where to find your logs**\n${ logHint } ` ) ,
201- )
202- : undefined ;
296+ // The log guide depends on the platform, so only show it once the platform is
297+ // known, and hide it while that answer is being edited. When editing another
298+ // field it renders above the question.
299+ const logComponent =
300+ editIndex !== 2 && values [ 2 ] !== undefined
301+ ? logGuideComponent ( values [ 1 ] , values [ 2 ] )
302+ : undefined ;
203303
204304 if ( editIndex !== undefined && logComponent ) {
205305 components . push ( logComponent , ...question ) ;
0 commit comments