2014-11-03 03:51:05 +00:00
/ *
2016-06-03 00:25:58 +00:00
Copyright 2014 The Kubernetes Authors .
2014-11-03 03:51:05 +00:00
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
package cmd
import (
2015-10-07 14:59:08 +00:00
"errors"
2017-05-03 10:32:15 +00:00
"fmt"
2014-11-03 03:51:05 +00:00
"io"
2015-09-10 03:46:11 +00:00
"math"
2015-05-21 20:14:32 +00:00
"os"
2015-09-10 03:46:11 +00:00
"time"
2014-12-03 12:15:48 +00:00
2015-08-05 22:05:17 +00:00
"github.com/spf13/cobra"
2017-01-11 14:09:48 +00:00
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
2017-01-19 18:27:59 +00:00
restclient "k8s.io/client-go/rest"
2017-11-08 22:34:54 +00:00
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/core/validation"
2016-10-07 22:24:42 +00:00
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
2015-08-05 22:03:47 +00:00
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
2017-05-19 21:33:08 +00:00
"k8s.io/kubernetes/pkg/kubectl/util"
2017-07-07 04:04:11 +00:00
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
2014-11-03 03:51:05 +00:00
)
2016-05-20 17:49:56 +00:00
var (
2017-02-16 03:47:00 +00:00
logsExample = templates . Examples ( i18n . T ( `
2016-05-20 17:49:56 +00:00
# Return snapshot logs from pod nginx with only one container
kubectl logs nginx
2014-12-15 11:07:25 +00:00
2017-05-03 10:32:15 +00:00
# Return snapshot logs from pod nginx with multi containers
kubectl logs nginx -- all - containers = true
# Return snapshot logs from all containers in pods defined by label app = nginx
kubectl logs - lapp = nginx -- all - containers = true
2016-09-15 01:23:00 +00:00
2016-05-20 17:49:56 +00:00
# Return snapshot of previous terminated ruby container logs from pod web - 1
kubectl logs - p - c ruby web - 1
2015-04-22 22:35:49 +00:00
2016-05-20 17:49:56 +00:00
# Begin streaming the logs of the ruby container in pod web - 1
kubectl logs - f - c ruby web - 1
2015-09-10 03:46:11 +00:00
2016-05-20 17:49:56 +00:00
# Display only the most recent 20 lines of output in pod nginx
kubectl logs -- tail = 20 nginx
2015-09-10 03:46:11 +00:00
2016-05-20 17:49:56 +00:00
# Show all logs from pod nginx written in the last hour
2017-02-16 11:46:54 +00:00
kubectl logs -- since = 1 h nginx
# Return snapshot logs from first container of a job named hello
kubectl logs job / hello
# Return snapshot logs from container nginx - 1 of a deployment named nginx
2017-03-15 03:49:10 +00:00
kubectl logs deployment / nginx - c nginx - 1 ` ) )
2016-09-15 01:23:00 +00:00
selectorTail int64 = 10
2015-02-20 21:28:43 +00:00
)
2015-02-03 17:59:21 +00:00
2016-08-30 05:27:22 +00:00
const (
2017-02-16 11:46:54 +00:00
logsUsageStr = "expected 'logs (POD | TYPE/NAME) [CONTAINER_NAME]'.\nPOD or TYPE/NAME is a required argument for the logs command"
2016-08-30 05:27:22 +00:00
)
2015-10-07 14:59:08 +00:00
type LogsOptions struct {
2017-05-03 10:32:15 +00:00
Namespace string
ResourceArg string
AllContainers bool
Options runtime . Object
2015-10-18 14:20:28 +00:00
2017-05-16 21:52:51 +00:00
Mapper meta . RESTMapper
Typer runtime . ObjectTyper
Decoder runtime . Decoder
2015-10-18 14:20:28 +00:00
2016-02-20 18:53:35 +00:00
Object runtime . Object
2017-02-21 16:19:13 +00:00
GetPodTimeout time . Duration
LogsForObject func ( object , options runtime . Object , timeout time . Duration ) ( * restclient . Request , error )
2015-10-07 14:59:08 +00:00
Out io . Writer
2015-06-30 00:48:00 +00:00
}
2017-06-09 03:26:06 +00:00
// NewCmdLogs creates a new pod logs command
2018-02-21 21:31:36 +00:00
func NewCmdLogs ( f cmdutil . Factory , out , errOut io . Writer ) * cobra . Command {
2015-10-18 14:20:28 +00:00
o := & LogsOptions { }
2015-02-20 21:28:43 +00:00
cmd := & cobra . Command {
2017-10-11 06:26:02 +00:00
Use : "logs [-f] [-p] (POD | TYPE/NAME) [-c CONTAINER]" ,
DisableFlagsInUseLine : true ,
2017-01-25 01:00:32 +00:00
Short : i18n . T ( "Print the logs for a container in a pod" ) ,
2017-02-16 11:46:54 +00:00
Long : "Print the logs for a container in a pod or specified resource. If the pod has only one container, the container name is optional." ,
2017-02-16 03:47:00 +00:00
Example : logsExample ,
2015-10-18 14:20:28 +00:00
PreRun : func ( cmd * cobra . Command , args [ ] string ) {
2015-10-07 14:59:08 +00:00
if len ( os . Args ) > 1 && os . Args [ 1 ] == "log" {
2018-02-21 21:31:36 +00:00
printDeprecationWarning ( errOut , "logs" , "log" )
2015-10-07 14:59:08 +00:00
}
2015-10-18 14:20:28 +00:00
} ,
Run : func ( cmd * cobra . Command , args [ ] string ) {
2015-10-07 14:59:08 +00:00
cmdutil . CheckErr ( o . Complete ( f , out , cmd , args ) )
2017-02-16 11:46:54 +00:00
cmdutil . CheckErr ( o . Validate ( ) )
2016-09-15 01:23:00 +00:00
cmdutil . CheckErr ( o . RunLogs ( ) )
2015-03-09 22:08:16 +00:00
} ,
2015-05-21 20:14:32 +00:00
Aliases : [ ] string { "log" } ,
2015-03-09 22:08:16 +00:00
}
2017-05-03 10:32:15 +00:00
cmd . Flags ( ) . Bool ( "all-containers" , false , "Get all containers's logs in the pod(s)." )
2015-10-18 14:20:28 +00:00
cmd . Flags ( ) . BoolP ( "follow" , "f" , false , "Specify if the logs should be streamed." )
cmd . Flags ( ) . Bool ( "timestamps" , false , "Include timestamps on each line in the log output" )
cmd . Flags ( ) . Int64 ( "limit-bytes" , 0 , "Maximum bytes of logs to return. Defaults to no limit." )
cmd . Flags ( ) . BoolP ( "previous" , "p" , false , "If true, print the logs for the previous instance of the container in a pod if it exists." )
2016-09-15 01:23:00 +00:00
cmd . Flags ( ) . Int64 ( "tail" , - 1 , "Lines of recent log file to display. Defaults to -1 with no selector, showing all log lines otherwise 10, if a selector is provided." )
2017-02-07 06:26:44 +00:00
cmd . Flags ( ) . String ( "since-time" , "" , i18n . T ( "Only return logs after a specific date (RFC3339). Defaults to all logs. Only one of since-time / since may be used." ) )
2015-10-18 14:20:28 +00:00
cmd . Flags ( ) . Duration ( "since" , 0 , "Only return logs newer than a relative duration like 5s, 2m, or 3h. Defaults to all logs. Only one of since-time / since may be used." )
cmd . Flags ( ) . StringP ( "container" , "c" , "" , "Print the logs of this container" )
cmd . Flags ( ) . Bool ( "interactive" , false , "If true, prompt the user for input when required." )
cmd . Flags ( ) . MarkDeprecated ( "interactive" , "This flag is no longer respected and there is no replacement." )
2017-02-21 16:19:13 +00:00
cmdutil . AddPodRunningTimeoutFlag ( cmd , defaultPodLogsTimeout )
2016-09-15 01:23:00 +00:00
cmd . Flags ( ) . StringP ( "selector" , "l" , "" , "Selector (label query) to filter on." )
2015-03-09 22:08:16 +00:00
return cmd
}
2014-11-25 18:10:32 +00:00
2016-10-13 00:18:39 +00:00
func ( o * LogsOptions ) Complete ( f cmdutil . Factory , out io . Writer , cmd * cobra . Command , args [ ] string ) error {
2015-10-18 14:20:28 +00:00
containerName := cmdutil . GetFlagString ( cmd , "container" )
2016-09-15 01:23:00 +00:00
selector := cmdutil . GetFlagString ( cmd , "selector" )
2017-05-03 10:32:15 +00:00
o . AllContainers = cmdutil . GetFlagBool ( cmd , "all-containers" )
2015-10-07 14:59:08 +00:00
switch len ( args ) {
case 0 :
2016-09-15 01:23:00 +00:00
if len ( selector ) == 0 {
2017-06-14 21:14:42 +00:00
return cmdutil . UsageErrorf ( cmd , "%s" , logsUsageStr )
2016-09-15 01:23:00 +00:00
}
2015-10-07 14:59:08 +00:00
case 1 :
2015-10-18 14:20:28 +00:00
o . ResourceArg = args [ 0 ]
2016-09-15 01:23:00 +00:00
if len ( selector ) != 0 {
2017-06-14 21:14:42 +00:00
return cmdutil . UsageErrorf ( cmd , "only a selector (-l) or a POD name is allowed" )
2016-09-15 01:23:00 +00:00
}
2015-10-07 14:59:08 +00:00
case 2 :
if cmd . Flag ( "container" ) . Changed {
2017-06-14 21:14:42 +00:00
return cmdutil . UsageErrorf ( cmd , "only one of -c or an inline [CONTAINER] arg is allowed" )
2015-10-07 14:59:08 +00:00
}
2015-10-18 14:20:28 +00:00
o . ResourceArg = args [ 0 ]
containerName = args [ 1 ]
2015-10-07 14:59:08 +00:00
default :
2017-06-14 21:14:42 +00:00
return cmdutil . UsageErrorf ( cmd , "%s" , logsUsageStr )
2015-09-10 03:46:11 +00:00
}
2015-10-07 14:59:08 +00:00
var err error
2015-10-18 14:20:28 +00:00
o . Namespace , _ , err = f . DefaultNamespace ( )
2015-03-09 22:08:16 +00:00
if err != nil {
return err
}
2014-12-11 18:39:20 +00:00
2015-10-18 14:20:28 +00:00
logOptions := & api . PodLogOptions {
Container : containerName ,
Follow : cmdutil . GetFlagBool ( cmd , "follow" ) ,
Previous : cmdutil . GetFlagBool ( cmd , "previous" ) ,
Timestamps : cmdutil . GetFlagBool ( cmd , "timestamps" ) ,
}
if sinceTime := cmdutil . GetFlagString ( cmd , "since-time" ) ; len ( sinceTime ) > 0 {
2017-05-19 21:33:08 +00:00
t , err := util . ParseRFC3339 ( sinceTime , metav1 . Now )
2015-10-07 14:59:08 +00:00
if err != nil {
return err
}
2015-10-18 14:20:28 +00:00
logOptions . SinceTime = & t
}
if limit := cmdutil . GetFlagInt64 ( cmd , "limit-bytes" ) ; limit != 0 {
logOptions . LimitBytes = & limit
}
2017-08-22 04:26:38 +00:00
tail := cmdutil . GetFlagInt64 ( cmd , "tail" )
if tail != - 1 {
2015-10-18 14:20:28 +00:00
logOptions . TailLines = & tail
}
if sinceSeconds := cmdutil . GetFlagDuration ( cmd , "since" ) ; sinceSeconds != 0 {
// round up to the nearest second
sec := int64 ( math . Ceil ( float64 ( sinceSeconds ) / float64 ( time . Second ) ) )
logOptions . SinceSeconds = & sec
2015-10-07 14:59:08 +00:00
}
2017-02-21 16:19:13 +00:00
o . GetPodTimeout , err = cmdutil . GetPodRunningTimeoutFlag ( cmd )
if err != nil {
return err
}
2015-10-18 14:20:28 +00:00
o . Options = logOptions
o . LogsForObject = f . LogsForObject
o . Out = out
2015-10-07 14:59:08 +00:00
2016-09-15 01:23:00 +00:00
if len ( selector ) != 0 {
if logOptions . Follow {
2017-06-14 21:14:42 +00:00
return cmdutil . UsageErrorf ( cmd , "only one of follow (-f) or selector (-l) is allowed" )
2016-09-15 01:23:00 +00:00
}
2017-08-22 04:26:38 +00:00
if logOptions . TailLines == nil && tail != - 1 {
2016-09-15 01:23:00 +00:00
logOptions . TailLines = & selectorTail
}
}
2016-02-20 18:53:35 +00:00
if o . Object == nil {
2017-08-02 20:23:07 +00:00
builder := f . NewBuilder ( ) .
2017-11-15 06:10:30 +00:00
Internal ( ) .
2016-02-20 18:53:35 +00:00
NamespaceParam ( o . Namespace ) . DefaultNamespace ( ) .
2016-09-15 01:23:00 +00:00
SingleResourceType ( )
if o . ResourceArg != "" {
builder . ResourceNames ( "pods" , o . ResourceArg )
}
if selector != "" {
2017-08-04 06:54:17 +00:00
builder . ResourceTypes ( "pods" ) . LabelSelectorParam ( selector )
2016-09-15 01:23:00 +00:00
}
infos , err := builder . Do ( ) . Infos ( )
2016-02-20 18:53:35 +00:00
if err != nil {
return err
}
2016-09-15 01:23:00 +00:00
if selector == "" && len ( infos ) != 1 {
2016-02-20 18:53:35 +00:00
return errors . New ( "expected a resource" )
}
o . Object = infos [ 0 ] . Object
}
2015-10-07 14:59:08 +00:00
return nil
}
2015-10-18 14:20:28 +00:00
func ( o LogsOptions ) Validate ( ) error {
2015-11-24 02:05:45 +00:00
logsOptions , ok := o . Options . ( * api . PodLogOptions )
2015-10-18 14:20:28 +00:00
if ! ok {
2015-11-24 02:05:45 +00:00
return errors . New ( "unexpected logs options object" )
2015-10-07 14:59:08 +00:00
}
2017-05-03 10:32:15 +00:00
if o . AllContainers && len ( logsOptions . Container ) > 0 {
return fmt . Errorf ( "--all-containers=true should not be specifiled with container name %s" , logsOptions . Container )
}
2015-11-24 02:05:45 +00:00
if errs := validation . ValidatePodLogOptions ( logsOptions ) ; len ( errs ) > 0 {
2015-11-04 00:08:20 +00:00
return errs . ToAggregate ( )
2015-10-07 14:59:08 +00:00
}
return nil
}
2014-12-11 18:39:20 +00:00
2015-11-24 02:05:45 +00:00
// RunLogs retrieves a pod log
2016-09-15 01:23:00 +00:00
func ( o LogsOptions ) RunLogs ( ) error {
switch t := o . Object . ( type ) {
case * api . PodList :
for _ , p := range t . Items {
2017-05-03 10:32:15 +00:00
if err := o . getPodLogs ( & p ) ; err != nil {
2016-09-15 01:23:00 +00:00
return err
}
}
return nil
2017-05-03 10:32:15 +00:00
case * api . Pod :
return o . getPodLogs ( t )
2016-09-15 01:23:00 +00:00
default :
return o . getLogs ( o . Object )
}
}
2017-05-03 10:32:15 +00:00
// getPodLogs checks whether o.AllContainers is set to true.
// If so, it retrives all containers' log in the pod.
func ( o LogsOptions ) getPodLogs ( pod * api . Pod ) error {
if ! o . AllContainers {
return o . getLogs ( pod )
}
for _ , c := range pod . Spec . InitContainers {
o . Options . ( * api . PodLogOptions ) . Container = c . Name
if err := o . getLogs ( pod ) ; err != nil {
return err
}
}
for _ , c := range pod . Spec . Containers {
o . Options . ( * api . PodLogOptions ) . Container = c . Name
if err := o . getLogs ( pod ) ; err != nil {
return err
}
}
return nil
}
2016-09-15 01:23:00 +00:00
func ( o LogsOptions ) getLogs ( obj runtime . Object ) error {
2017-02-21 16:19:13 +00:00
req , err := o . LogsForObject ( obj , o . Options , o . GetPodTimeout )
2015-10-18 14:20:28 +00:00
if err != nil {
2016-09-15 01:23:00 +00:00
return err
2015-09-10 03:46:11 +00:00
}
readCloser , err := req . Stream ( )
2015-03-09 22:08:16 +00:00
if err != nil {
2016-09-15 01:23:00 +00:00
return err
2015-03-09 22:08:16 +00:00
}
defer readCloser . Close ( )
2015-10-18 14:20:28 +00:00
2016-09-15 01:23:00 +00:00
_ , err = io . Copy ( o . Out , readCloser )
return err
2014-11-03 03:51:05 +00:00
}