@@ -3,13 +3,18 @@ package koyeb
3
3
import (
4
4
"context"
5
5
"fmt"
6
+ "github.com/gorilla/websocket"
6
7
"github.com/koyeb/koyeb-api-client-go/api/v1/koyeb"
7
8
"github.com/logrusorgru/aurora"
8
9
"github.com/pkg/errors"
10
+ log "github.com/sirupsen/logrus"
9
11
"github.com/spf13/cobra"
10
12
"github.com/spf13/pflag"
13
+ "net/http"
14
+ "net/url"
11
15
"strconv"
12
16
"strings"
17
+ "time"
13
18
)
14
19
15
20
func addServiceDefinitionFlags (flags * pflag.FlagSet ) {
@@ -162,6 +167,17 @@ func NewServiceCmd() *cobra.Command {
162
167
}
163
168
serviceCmd .AddCommand (getServiceCmd )
164
169
170
+ logsServiceCmd := & cobra.Command {
171
+ Use : "logs [name]" ,
172
+ Aliases : []string {"l" , "log" },
173
+ Short : "Get the service logs" ,
174
+ Args : cobra .ExactArgs (1 ),
175
+ RunE : h .Log ,
176
+ }
177
+ serviceCmd .AddCommand (logsServiceCmd )
178
+ logsServiceCmd .Flags ().Bool ("stderr" , false , "Get stderr stream" )
179
+ logsServiceCmd .Flags ().String ("instance" , "" , "Instance" )
180
+
165
181
listServiceCmd := & cobra.Command {
166
182
Use : "list" ,
167
183
Short : "List services" ,
@@ -260,6 +276,110 @@ func (h *ServiceHandler) Get(cmd *cobra.Command, args []string) error {
260
276
return h .getFormat (cmd , args , format )
261
277
}
262
278
279
+ func (h * ServiceHandler ) Log (cmd * cobra.Command , args []string ) error {
280
+ client := getApiClient ()
281
+ ctx := getAuth (context .Background ())
282
+ app := getSelectedApp ()
283
+ _ , _ , err := client .ServicesApi .GetService (ctx , app , args [0 ]).Execute ()
284
+ if err != nil {
285
+ fatalApiError (err )
286
+ }
287
+ revDetail , _ , err := client .ServicesApi .GetRevision (ctx , app , args [0 ], "_latest" ).Execute ()
288
+ if err != nil {
289
+ fatalApiError (err )
290
+ }
291
+ instances := revDetail .Revision .State .GetInstances ()
292
+ if len (instances ) == 0 {
293
+ log .Fatal ("Unable to attach to instance" )
294
+ }
295
+ instance := instances [0 ].GetId ()
296
+ selectedInstance , _ := cmd .Flags ().GetString ("instance" )
297
+ if selectedInstance != "" {
298
+ instance = selectedInstance
299
+ }
300
+ done := make (chan struct {})
301
+ stream := "stdout"
302
+ stderr , _ := cmd .Flags ().GetBool ("stderr" )
303
+ if stderr {
304
+ stream = "stderr"
305
+ }
306
+ return watchLog (app , args [0 ], revDetail .Revision .GetId (), instance , stream , done , "" )
307
+ }
308
+
309
+ type LogMessageResult struct {
310
+ Msg string
311
+ }
312
+
313
+ type LogMessage struct {
314
+ Result LogMessageResult
315
+ }
316
+
317
+ func (l LogMessage ) String () string {
318
+ return l .Result .Msg
319
+ }
320
+
321
+ func watchLog (app string , service string , revision string , instance string , stream string , done chan struct {}, filter string ) error {
322
+ path := fmt .Sprintf ("/v1/apps/%s/services/%s/revisions/%s/instances/%s/logs/%s/tail" , app , service , revision , instance , stream )
323
+
324
+ u , err := url .Parse (apiurl )
325
+ if err != nil {
326
+ er (err )
327
+ }
328
+
329
+ u .Path = path
330
+ if u .Scheme == "https" {
331
+ u .Scheme = "wss"
332
+ } else {
333
+ u .Scheme = "ws"
334
+ }
335
+
336
+ if filter != "" {
337
+ u .RawQuery = filter
338
+ }
339
+
340
+ log .Debugf ("Gettings logs from %v" , u .String ())
341
+
342
+ h := http.Header {"Sec-Websocket-Protocol" : []string {fmt .Sprintf ("Bearer, %s" , token )}}
343
+ c , _ , err := websocket .DefaultDialer .Dial (u .String (), h )
344
+ if err != nil {
345
+ log .Fatal ("dial:" , err )
346
+ }
347
+ defer c .Close ()
348
+
349
+ readDone := make (chan struct {})
350
+
351
+ go func () {
352
+ defer close (done )
353
+ for {
354
+ msg := LogMessage {}
355
+ err := c .ReadJSON (& msg )
356
+ if err != nil {
357
+ log .Println ("error:" , err )
358
+ return
359
+ }
360
+ log .Printf ("%s" , msg )
361
+ }
362
+ }()
363
+
364
+ ticker := time .NewTicker (10 * time .Second )
365
+ defer ticker .Stop ()
366
+
367
+ for {
368
+ select {
369
+ case <- done :
370
+ return nil
371
+ case <- readDone :
372
+ return nil
373
+ case t := <- ticker .C :
374
+ err := c .WriteMessage (websocket .PingMessage , []byte (t .String ()))
375
+ if err != nil {
376
+ log .Println ("write:" , err )
377
+ return err
378
+ }
379
+ }
380
+ }
381
+ }
382
+
263
383
func (h * ServiceHandler ) Describe (cmd * cobra.Command , args []string ) error {
264
384
format := getFormat ("detail" )
265
385
if len (args ) == 0 {
0 commit comments