mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-30 15:05:27 +00:00
Merge pull request #124671 from saschagrunert/logs-staging
Move `pkg/kubelet/kuberuntime/logs` to `k8s.io/cri-client` staging
This commit is contained in:
commit
a0e3a70d53
@ -21,8 +21,9 @@ import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/kubernetes/pkg/kubelet/kuberuntime/logs"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/cri-client/pkg/logs"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
// ReadLogs read the container log and redirect into stdout and stderr.
|
||||
@ -31,6 +32,6 @@ import (
|
||||
func (m *kubeGenericRuntimeManager) ReadLogs(ctx context.Context, path, containerID string, apiOpts *v1.PodLogOptions, stdout, stderr io.Writer) error {
|
||||
// Convert v1.PodLogOptions into internal log options.
|
||||
opts := logs.NewLogOptions(apiOpts, time.Now())
|
||||
|
||||
return logs.ReadLogs(ctx, path, containerID, opts, m.runtimeService, stdout, stderr)
|
||||
logger := klog.Background()
|
||||
return logs.ReadLogs(ctx, &logger, path, containerID, opts, m.runtimeService, stdout, stderr)
|
||||
}
|
||||
|
@ -19,10 +19,6 @@ package types
|
||||
const (
|
||||
// ResolvConfDefault is the system default DNS resolver configuration.
|
||||
ResolvConfDefault = "/etc/resolv.conf"
|
||||
// RFC3339NanoFixed is the fixed width version of time.RFC3339Nano.
|
||||
RFC3339NanoFixed = "2006-01-02T15:04:05.000000000Z07:00"
|
||||
// RFC3339NanoLenient is the variable width RFC3339 time format for lenient parsing of strings into timestamps.
|
||||
RFC3339NanoLenient = "2006-01-02T15:04:05.999999999Z07:00"
|
||||
)
|
||||
|
||||
// User visible keys for managing node allocatable enforcement on the node.
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/cri-client/pkg/logs"
|
||||
)
|
||||
|
||||
// TODO: Reconcile custom types in kubelet/types and this subpackage
|
||||
@ -45,7 +46,7 @@ func NewTimestamp() *Timestamp {
|
||||
// ConvertToTimestamp takes a string, parses it using the RFC3339NanoLenient layout,
|
||||
// and converts it to a Timestamp object.
|
||||
func ConvertToTimestamp(timeString string) *Timestamp {
|
||||
parsed, _ := time.Parse(RFC3339NanoLenient, timeString)
|
||||
parsed, _ := time.Parse(logs.RFC3339NanoLenient, timeString)
|
||||
return &Timestamp{parsed}
|
||||
}
|
||||
|
||||
@ -57,7 +58,7 @@ func (t *Timestamp) Get() time.Time {
|
||||
// GetString returns the time in the string format using the RFC3339NanoFixed
|
||||
// layout.
|
||||
func (t *Timestamp) GetString() string {
|
||||
return t.time.Format(RFC3339NanoFixed)
|
||||
return t.time.Format(logs.RFC3339NanoFixed)
|
||||
}
|
||||
|
||||
// SortedContainerStatuses is a type to help sort container statuses based on container names.
|
||||
|
@ -17,7 +17,6 @@ limitations under the License.
|
||||
package tail
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
@ -27,11 +26,6 @@ const (
|
||||
blockSize = 1024
|
||||
)
|
||||
|
||||
var (
|
||||
// eol is the end-of-line sign in the log.
|
||||
eol = []byte{'\n'}
|
||||
)
|
||||
|
||||
// ReadAtMost reads at most max bytes from the end of the file identified by path or
|
||||
// returns an error. It returns true if the file was longer than max. It will
|
||||
// allocate up to max bytes.
|
||||
@ -59,40 +53,3 @@ func ReadAtMost(path string, max int64) ([]byte, bool, error) {
|
||||
data, err := io.ReadAll(f)
|
||||
return data, offset > 0, err
|
||||
}
|
||||
|
||||
// FindTailLineStartIndex returns the start of last nth line.
|
||||
// * If n < 0, return the beginning of the file.
|
||||
// * If n >= 0, return the beginning of last nth line.
|
||||
// Notice that if the last line is incomplete (no end-of-line), it will not be counted
|
||||
// as one line.
|
||||
func FindTailLineStartIndex(f io.ReadSeeker, n int64) (int64, error) {
|
||||
if n < 0 {
|
||||
return 0, nil
|
||||
}
|
||||
size, err := f.Seek(0, io.SeekEnd)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
var left, cnt int64
|
||||
buf := make([]byte, blockSize)
|
||||
for right := size; right > 0 && cnt <= n; right -= blockSize {
|
||||
left = right - blockSize
|
||||
if left < 0 {
|
||||
left = 0
|
||||
buf = make([]byte, right)
|
||||
}
|
||||
if _, err := f.Seek(left, io.SeekStart); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if _, err := f.Read(buf); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
cnt += int64(bytes.Count(buf, eol))
|
||||
}
|
||||
for ; cnt > n; cnt-- {
|
||||
idx := bytes.Index(buf, eol) + 1
|
||||
buf = buf[idx:]
|
||||
left += int64(idx)
|
||||
}
|
||||
return left, nil
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ limitations under the License.
|
||||
package tail
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
@ -89,32 +88,3 @@ func TestReadAtMost(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTail(t *testing.T) {
|
||||
line := strings.Repeat("a", blockSize)
|
||||
testBytes := []byte(line + "\n" +
|
||||
line + "\n" +
|
||||
line + "\n" +
|
||||
line + "\n" +
|
||||
line[blockSize/2:]) // incomplete line
|
||||
|
||||
for c, test := range []struct {
|
||||
n int64
|
||||
start int64
|
||||
}{
|
||||
{n: -1, start: 0},
|
||||
{n: 0, start: int64(len(line)+1) * 4},
|
||||
{n: 1, start: int64(len(line)+1) * 3},
|
||||
{n: 9999, start: 0},
|
||||
} {
|
||||
t.Logf("TestCase #%d: %+v", c, test)
|
||||
r := bytes.NewReader(testBytes)
|
||||
s, err := FindTailLineStartIndex(r, test.n)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if s != test.start {
|
||||
t.Errorf("%d != %d", s, test.start)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -305,8 +305,10 @@
|
||||
|
||||
- baseImportPath: "./staging/src/k8s.io/cri-client"
|
||||
allowedImports:
|
||||
- k8s.io/api
|
||||
- k8s.io/apimachinery
|
||||
- k8s.io/apiserver
|
||||
- k8s.io/client-go
|
||||
- k8s.io/component-base
|
||||
- k8s.io/cri-api
|
||||
- k8s.io/cri-client
|
||||
|
@ -6,13 +6,16 @@ go 1.22.0
|
||||
|
||||
require (
|
||||
github.com/Microsoft/go-winio v0.6.0
|
||||
github.com/fsnotify/fsnotify v1.7.0
|
||||
github.com/stretchr/testify v1.8.4
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0
|
||||
go.opentelemetry.io/otel/sdk v1.20.0
|
||||
go.opentelemetry.io/otel/trace v1.20.0
|
||||
golang.org/x/sys v0.20.0
|
||||
google.golang.org/grpc v1.59.0
|
||||
k8s.io/api v0.0.0
|
||||
k8s.io/apimachinery v0.0.0
|
||||
k8s.io/client-go v0.0.0
|
||||
k8s.io/component-base v0.0.0
|
||||
k8s.io/cri-api v0.0.0
|
||||
k8s.io/klog/v2 v2.120.1
|
||||
@ -25,12 +28,25 @@ require (
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.3 // indirect
|
||||
github.com/go-logr/logr v1.4.1 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||
github.com/go-openapi/swag v0.22.4 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/google/gnostic-models v0.6.8 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/uuid v1.3.1 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/prometheus/client_golang v1.19.0 // indirect
|
||||
github.com/prometheus/client_model v0.6.0 // indirect
|
||||
@ -53,9 +69,12 @@ require (
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/client-go v0.0.0 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
|
||||
)
|
||||
|
||||
replace (
|
||||
|
43
staging/src/k8s.io/cri-client/go.sum
generated
43
staging/src/k8s.io/cri-client/go.sum
generated
@ -5,10 +5,12 @@ cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1h
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg=
|
||||
github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE=
|
||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||
github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE=
|
||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
|
||||
@ -21,14 +23,20 @@ github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
|
||||
github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k=
|
||||
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
|
||||
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE=
|
||||
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
|
||||
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
github.com/fxamacker/cbor/v2 v2.6.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
|
||||
github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
|
||||
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||
@ -38,8 +46,12 @@ github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ4
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
|
||||
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
||||
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
||||
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
|
||||
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
|
||||
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||
github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
|
||||
github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
@ -50,11 +62,16 @@ github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4er
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
|
||||
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
|
||||
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
|
||||
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
|
||||
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
@ -62,21 +79,31 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rH
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
|
||||
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
|
||||
github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
||||
@ -84,6 +111,7 @@ github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0
|
||||
github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
|
||||
@ -101,7 +129,13 @@ github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic
|
||||
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||
@ -175,6 +209,7 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d h1:VBu5YqKPv6XiJ199exd8Br+Aetz+o08F+PLMnwJQHAY=
|
||||
google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4=
|
||||
@ -190,16 +225,24 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
|
||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
k8s.io/gengo/v2 v2.0.0-20240228010128-51d4e06bde70/go.mod h1:VH3AT8AaQOqiGjMF9p0/IM1Dj+82ZwjfxUP1IxaHE+8=
|
||||
k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw=
|
||||
k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag=
|
||||
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98=
|
||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI=
|
||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
|
||||
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||
|
33
staging/src/k8s.io/cri-client/pkg/internal/log.go
Normal file
33
staging/src/k8s.io/cri-client/pkg/internal/log.go
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
Copyright 2024 The Kubernetes Authors.
|
||||
|
||||
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 internal
|
||||
|
||||
import "k8s.io/klog/v2"
|
||||
|
||||
func Log(logger *klog.Logger, level int, msg string, keyAndValues ...any) {
|
||||
if logger == nil {
|
||||
return
|
||||
}
|
||||
logger.V(level).Info(msg, keyAndValues...)
|
||||
}
|
||||
|
||||
func LogErr(logger *klog.Logger, err error, msg string, keyAndValues ...any) {
|
||||
if logger == nil {
|
||||
return
|
||||
}
|
||||
logger.Error(err, msg, keyAndValues...)
|
||||
}
|
@ -30,14 +30,14 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
internalapi "k8s.io/cri-api/pkg/apis"
|
||||
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
remote "k8s.io/cri-client/pkg"
|
||||
"k8s.io/kubernetes/pkg/kubelet/types"
|
||||
"k8s.io/kubernetes/pkg/util/tail"
|
||||
"k8s.io/cri-client/pkg/internal"
|
||||
)
|
||||
|
||||
// Notice that the current CRI logs implementation doesn't handle
|
||||
@ -46,13 +46,17 @@ import (
|
||||
// * If log rotation happens when following the log:
|
||||
// * If the rotation is using create mode, we'll still follow the old file.
|
||||
// * If the rotation is using copytruncate, we'll be reading at the original position and get nothing.
|
||||
// TODO(random-liu): Support log rotation.
|
||||
|
||||
const (
|
||||
// RFC3339NanoFixed is the fixed width version of time.RFC3339Nano.
|
||||
RFC3339NanoFixed = "2006-01-02T15:04:05.000000000Z07:00"
|
||||
// RFC3339NanoLenient is the variable width RFC3339 time format for lenient parsing of strings into timestamps.
|
||||
RFC3339NanoLenient = "2006-01-02T15:04:05.999999999Z07:00"
|
||||
|
||||
// timeFormatOut is the format for writing timestamps to output.
|
||||
timeFormatOut = types.RFC3339NanoFixed
|
||||
timeFormatOut = RFC3339NanoFixed
|
||||
// timeFormatIn is the format for parsing timestamps from other logs.
|
||||
timeFormatIn = types.RFC3339NanoLenient
|
||||
timeFormatIn = RFC3339NanoLenient
|
||||
|
||||
// logForceCheckPeriod is the period to check for a new read
|
||||
logForceCheckPeriod = 1 * time.Second
|
||||
@ -280,7 +284,7 @@ func (w *logWriter) write(msg *logMessage, addPrefix bool) error {
|
||||
// ReadLogs read the container log and redirect into stdout and stderr.
|
||||
// Note that containerID is only needed when following the log, or else
|
||||
// just pass in empty string "".
|
||||
func ReadLogs(ctx context.Context, path, containerID string, opts *LogOptions, runtimeService internalapi.RuntimeService, stdout, stderr io.Writer) error {
|
||||
func ReadLogs(ctx context.Context, logger *klog.Logger, path, containerID string, opts *LogOptions, runtimeService internalapi.RuntimeService, stdout, stderr io.Writer) error {
|
||||
// fsnotify has different behavior for symlinks in different platform,
|
||||
// for example it follows symlink on Linux, but not on Windows,
|
||||
// so we explicitly resolve symlinks before reading the logs.
|
||||
@ -298,7 +302,7 @@ func ReadLogs(ctx context.Context, path, containerID string, opts *LogOptions, r
|
||||
defer f.Close()
|
||||
|
||||
// Search start point based on tail line.
|
||||
start, err := tail.FindTailLineStartIndex(f, opts.tail)
|
||||
start, err := findTailLineStartIndex(f, opts.tail)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to tail %d lines of log file %q: %v", opts.tail, path, err)
|
||||
}
|
||||
@ -322,7 +326,7 @@ func ReadLogs(ctx context.Context, path, containerID string, opts *LogOptions, r
|
||||
dir := filepath.Dir(path)
|
||||
for {
|
||||
if stop || (limitedMode && limitedNum == 0) {
|
||||
klog.V(2).InfoS("Finished parsing log file", "path", path)
|
||||
internal.Log(logger, 2, "Finished parsing log file", "path", path)
|
||||
return nil
|
||||
}
|
||||
l, err := r.ReadBytes(eol[0])
|
||||
@ -355,7 +359,7 @@ func ReadLogs(ctx context.Context, path, containerID string, opts *LogOptions, r
|
||||
}
|
||||
var recreated bool
|
||||
// Wait until the next log change.
|
||||
found, recreated, err = waitLogs(ctx, containerID, baseName, watcher, runtimeService)
|
||||
found, recreated, err = waitLogs(ctx, logger, containerID, baseName, watcher, runtimeService)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -380,7 +384,7 @@ func ReadLogs(ctx context.Context, path, containerID string, opts *LogOptions, r
|
||||
if len(l) == 0 {
|
||||
continue
|
||||
}
|
||||
klog.InfoS("Incomplete line in log file", "path", path, "line", l)
|
||||
internal.Log(logger, 0, "Incomplete line in log file", "path", path, "line", l)
|
||||
}
|
||||
if parse == nil {
|
||||
// Initialize the log parsing function.
|
||||
@ -392,16 +396,16 @@ func ReadLogs(ctx context.Context, path, containerID string, opts *LogOptions, r
|
||||
// Parse the log line.
|
||||
msg.reset()
|
||||
if err := parse(l, msg); err != nil {
|
||||
klog.ErrorS(err, "Failed when parsing line in log file", "path", path, "line", l)
|
||||
internal.LogErr(logger, err, "Failed when parsing line in log file", "path", path, "line", l)
|
||||
continue
|
||||
}
|
||||
// Write the log line into the stream.
|
||||
if err := writer.write(msg, isNewLine); err != nil {
|
||||
if err == errMaximumWrite {
|
||||
klog.V(2).InfoS("Finished parsing log file, hit bytes limit", "path", path, "limit", opts.bytes)
|
||||
internal.Log(logger, 2, "Finished parsing log file, hit bytes limit", "path", path, "limit", opts.bytes)
|
||||
return nil
|
||||
}
|
||||
klog.ErrorS(err, "Failed when writing line to log file", "path", path, "line", msg)
|
||||
internal.LogErr(logger, err, "Failed when writing line to log file", "path", path, "line", msg)
|
||||
return err
|
||||
}
|
||||
if limitedMode {
|
||||
@ -415,7 +419,7 @@ func ReadLogs(ctx context.Context, path, containerID string, opts *LogOptions, r
|
||||
}
|
||||
}
|
||||
|
||||
func isContainerRunning(ctx context.Context, id string, r internalapi.RuntimeService) (bool, error) {
|
||||
func isContainerRunning(ctx context.Context, logger *klog.Logger, id string, r internalapi.RuntimeService) (bool, error) {
|
||||
resp, err := r.ContainerStatus(ctx, id, false)
|
||||
if err != nil {
|
||||
return false, err
|
||||
@ -426,7 +430,7 @@ func isContainerRunning(ctx context.Context, id string, r internalapi.RuntimeSer
|
||||
}
|
||||
// Only keep following container log when it is running.
|
||||
if status.State != runtimeapi.ContainerState_CONTAINER_RUNNING {
|
||||
klog.V(5).InfoS("Container is not running", "containerId", id, "state", status.State)
|
||||
internal.Log(logger, 5, "Container is not running", "containerId", id, "state", status.State)
|
||||
// Do not return error because it's normal that the container stops
|
||||
// during waiting.
|
||||
return false, nil
|
||||
@ -437,9 +441,9 @@ func isContainerRunning(ctx context.Context, id string, r internalapi.RuntimeSer
|
||||
// waitLogs wait for the next log write. It returns two booleans and an error. The first boolean
|
||||
// indicates whether a new log is found; the second boolean if the log file was recreated;
|
||||
// the error is error happens during waiting new logs.
|
||||
func waitLogs(ctx context.Context, id string, logName string, w *fsnotify.Watcher, runtimeService internalapi.RuntimeService) (bool, bool, error) {
|
||||
func waitLogs(ctx context.Context, logger *klog.Logger, id string, logName string, w *fsnotify.Watcher, runtimeService internalapi.RuntimeService) (bool, bool, error) {
|
||||
// no need to wait if the pod is not running
|
||||
if running, err := isContainerRunning(ctx, id, runtimeService); !running {
|
||||
if running, err := isContainerRunning(ctx, logger, id, runtimeService); !running {
|
||||
return false, false, err
|
||||
}
|
||||
errRetry := 5
|
||||
@ -454,10 +458,10 @@ func waitLogs(ctx context.Context, id string, logName string, w *fsnotify.Watche
|
||||
case fsnotify.Create:
|
||||
return true, filepath.Base(e.Name) == logName, nil
|
||||
default:
|
||||
klog.ErrorS(nil, "Received unexpected fsnotify event, retrying", "event", e)
|
||||
internal.LogErr(logger, nil, "Received unexpected fsnotify event, retrying", "event", e)
|
||||
}
|
||||
case err := <-w.Errors:
|
||||
klog.ErrorS(err, "Received fsnotify watch error, retrying unless no more retries left", "retries", errRetry)
|
||||
internal.LogErr(logger, err, "Received fsnotify watch error, retrying unless no more retries left", "retries", errRetry)
|
||||
if errRetry == 0 {
|
||||
return false, false, err
|
||||
}
|
@ -28,17 +28,14 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
utiltesting "k8s.io/client-go/util/testing"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
apitesting "k8s.io/cri-api/pkg/apis/testing"
|
||||
"k8s.io/kubernetes/pkg/kubelet/types"
|
||||
"k8s.io/utils/pointer"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
utiltesting "k8s.io/client-go/util/testing"
|
||||
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
|
||||
apitesting "k8s.io/cri-api/pkg/apis/testing"
|
||||
"k8s.io/utils/ptr"
|
||||
)
|
||||
|
||||
func TestLogOptions(t *testing.T) {
|
||||
@ -102,42 +99,42 @@ func TestReadLogs(t *testing.T) {
|
||||
{
|
||||
name: "using TailLines 2 should output last 2 lines",
|
||||
podLogOptions: v1.PodLogOptions{
|
||||
TailLines: pointer.Int64(2),
|
||||
TailLines: ptr.To[int64](2),
|
||||
},
|
||||
expected: "line2\nline3\n",
|
||||
},
|
||||
{
|
||||
name: "using TailLines 4 should output all lines when the log has less than 4 lines",
|
||||
podLogOptions: v1.PodLogOptions{
|
||||
TailLines: pointer.Int64(4),
|
||||
TailLines: ptr.To[int64](4),
|
||||
},
|
||||
expected: "line1\nline2\nline3\n",
|
||||
},
|
||||
{
|
||||
name: "using TailLines 0 should output nothing",
|
||||
podLogOptions: v1.PodLogOptions{
|
||||
TailLines: pointer.Int64(0),
|
||||
TailLines: ptr.To[int64](0),
|
||||
},
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
name: "using LimitBytes 9 should output first 9 bytes",
|
||||
podLogOptions: v1.PodLogOptions{
|
||||
LimitBytes: pointer.Int64(9),
|
||||
LimitBytes: ptr.To[int64](9),
|
||||
},
|
||||
expected: "line1\nlin",
|
||||
},
|
||||
{
|
||||
name: "using LimitBytes 100 should output all bytes when the log has less than 100 bytes",
|
||||
podLogOptions: v1.PodLogOptions{
|
||||
LimitBytes: pointer.Int64(100),
|
||||
LimitBytes: ptr.To[int64](100),
|
||||
},
|
||||
expected: "line1\nline2\nline3\n",
|
||||
},
|
||||
{
|
||||
name: "using LimitBytes 0 should output nothing",
|
||||
podLogOptions: v1.PodLogOptions{
|
||||
LimitBytes: pointer.Int64(0),
|
||||
LimitBytes: ptr.To[int64](0),
|
||||
},
|
||||
expected: "",
|
||||
},
|
||||
@ -166,7 +163,7 @@ func TestReadLogs(t *testing.T) {
|
||||
name: "using follow combined with TailLines 2 should output the last 2 lines",
|
||||
podLogOptions: v1.PodLogOptions{
|
||||
Follow: true,
|
||||
TailLines: pointer.Int64(2),
|
||||
TailLines: ptr.To[int64](2),
|
||||
},
|
||||
expected: "line2\nline3\n",
|
||||
},
|
||||
@ -199,7 +196,7 @@ func TestReadLogs(t *testing.T) {
|
||||
opts := NewLogOptions(&tc.podLogOptions, time.Now())
|
||||
stdoutBuf := bytes.NewBuffer(nil)
|
||||
stderrBuf := bytes.NewBuffer(nil)
|
||||
err = ReadLogs(context.TODO(), file.Name(), containerID, opts, fakeRuntimeService, stdoutBuf, stderrBuf)
|
||||
err = ReadLogs(context.TODO(), nil, file.Name(), containerID, opts, fakeRuntimeService, stdoutBuf, stderrBuf)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
@ -245,7 +242,7 @@ func TestReadRotatedLog(t *testing.T) {
|
||||
Follow: true,
|
||||
}
|
||||
opts := NewLogOptions(&podLogOptions, time.Now())
|
||||
_ = ReadLogs(ctx, fileName, containerID, opts, fakeRuntimeService, stdoutBuf, stderrBuf)
|
||||
_ = ReadLogs(ctx, nil, fileName, containerID, opts, fakeRuntimeService, stdoutBuf, stderrBuf)
|
||||
}(ctx)
|
||||
|
||||
// log in stdout
|
||||
@ -262,7 +259,7 @@ func TestReadRotatedLog(t *testing.T) {
|
||||
|
||||
for line := 0; line < 10; line++ {
|
||||
// Write the first three lines to log file
|
||||
now := time.Now().Format(types.RFC3339NanoLenient)
|
||||
now := time.Now().Format(RFC3339NanoLenient)
|
||||
if line%2 == 0 {
|
||||
file.WriteString(fmt.Sprintf(
|
||||
`{"log":"line%d\n","stream":"stdout","time":"%s"}`+"\n", line, now))
|
||||
@ -523,7 +520,7 @@ func TestReadLogsLimitsWithTimestamps(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
w := io.MultiWriter(&buf)
|
||||
|
||||
err = ReadLogs(context.Background(), tmpfile.Name(), "", &LogOptions{tail: -1, bytes: -1, timestamp: true}, nil, w, w)
|
||||
err = ReadLogs(context.Background(), nil, tmpfile.Name(), "", &LogOptions{tail: -1, bytes: -1, timestamp: true}, nil, w, w)
|
||||
assert.NoError(t, err)
|
||||
|
||||
lineCount := 0
|
62
staging/src/k8s.io/cri-client/pkg/logs/tail.go
Normal file
62
staging/src/k8s.io/cri-client/pkg/logs/tail.go
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
Copyright 2024 The Kubernetes Authors.
|
||||
|
||||
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 logs
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
)
|
||||
|
||||
// blockSize is the block size used in tail.
|
||||
const blockSize = 1024
|
||||
|
||||
// findTailLineStartIndex returns the start of last nth line.
|
||||
// * If n < 0, return the beginning of the file.
|
||||
// * If n >= 0, return the beginning of last nth line.
|
||||
// Notice that if the last line is incomplete (no end-of-line), it will not be counted
|
||||
// as one line.
|
||||
func findTailLineStartIndex(f io.ReadSeeker, n int64) (int64, error) {
|
||||
if n < 0 {
|
||||
return 0, nil
|
||||
}
|
||||
size, err := f.Seek(0, io.SeekEnd)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
var left, cnt int64
|
||||
buf := make([]byte, blockSize)
|
||||
for right := size; right > 0 && cnt <= n; right -= blockSize {
|
||||
left = right - blockSize
|
||||
if left < 0 {
|
||||
left = 0
|
||||
buf = make([]byte, right)
|
||||
}
|
||||
if _, err := f.Seek(left, io.SeekStart); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if _, err := f.Read(buf); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
cnt += int64(bytes.Count(buf, eol))
|
||||
}
|
||||
for ; cnt > n; cnt-- {
|
||||
idx := bytes.Index(buf, eol) + 1
|
||||
buf = buf[idx:]
|
||||
left += int64(idx)
|
||||
}
|
||||
return left, nil
|
||||
}
|
52
staging/src/k8s.io/cri-client/pkg/logs/tail_test.go
Normal file
52
staging/src/k8s.io/cri-client/pkg/logs/tail_test.go
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
Copyright 2024 The Kubernetes Authors.
|
||||
|
||||
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 logs
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTail(t *testing.T) {
|
||||
line := strings.Repeat("a", blockSize)
|
||||
testBytes := []byte(line + "\n" +
|
||||
line + "\n" +
|
||||
line + "\n" +
|
||||
line + "\n" +
|
||||
line[blockSize/2:]) // incomplete line
|
||||
|
||||
for c, test := range []struct {
|
||||
n int64
|
||||
start int64
|
||||
}{
|
||||
{n: -1, start: 0},
|
||||
{n: 0, start: int64(len(line)+1) * 4},
|
||||
{n: 1, start: int64(len(line)+1) * 3},
|
||||
{n: 9999, start: 0},
|
||||
} {
|
||||
t.Logf("TestCase #%d: %+v", c, test)
|
||||
r := bytes.NewReader(testBytes)
|
||||
s, err := findTailLineStartIndex(r, test.n)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if s != test.start {
|
||||
t.Errorf("%d != %d", s, test.start)
|
||||
}
|
||||
}
|
||||
}
|
@ -29,12 +29,14 @@ import (
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
"google.golang.org/grpc/status"
|
||||
tracing "k8s.io/component-base/tracing"
|
||||
"k8s.io/cri-client/pkg/util"
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
tracing "k8s.io/component-base/tracing"
|
||||
internalapi "k8s.io/cri-api/pkg/apis"
|
||||
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
"k8s.io/cri-client/pkg/internal"
|
||||
"k8s.io/cri-client/pkg/util"
|
||||
)
|
||||
|
||||
// remoteImageService is a gRPC implementation of internalapi.ImageManagerService.
|
||||
@ -46,7 +48,7 @@ type remoteImageService struct {
|
||||
|
||||
// NewRemoteImageService creates a new internalapi.ImageManagerService.
|
||||
func NewRemoteImageService(endpoint string, connectionTimeout time.Duration, tp trace.TracerProvider, logger *klog.Logger) (internalapi.ImageManagerService, error) {
|
||||
log(logger, 3, "Connecting to image service", "endpoint", endpoint)
|
||||
internal.Log(logger, 3, "Connecting to image service", "endpoint", endpoint)
|
||||
addr, dialer, err := util.GetAddressAndDialer(endpoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -86,7 +88,7 @@ func NewRemoteImageService(endpoint string, connectionTimeout time.Duration, tp
|
||||
|
||||
conn, err := grpc.DialContext(ctx, addr, dialOpts...)
|
||||
if err != nil {
|
||||
logErr(logger, err, "Connect remote image service failed", "address", addr)
|
||||
internal.LogErr(logger, err, "Connect remote image service failed", "address", addr)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -103,11 +105,11 @@ func NewRemoteImageService(endpoint string, connectionTimeout time.Duration, tp
|
||||
}
|
||||
|
||||
func (r *remoteImageService) log(level int, msg string, keyAndValues ...any) {
|
||||
log(r.logger, level, msg, keyAndValues...)
|
||||
internal.Log(r.logger, level, msg, keyAndValues...)
|
||||
}
|
||||
|
||||
func (r *remoteImageService) logErr(err error, msg string, keyAndValues ...any) {
|
||||
logErr(r.logger, err, msg, keyAndValues...)
|
||||
internal.LogErr(r.logger, err, msg, keyAndValues...)
|
||||
}
|
||||
|
||||
// validateServiceConnection tries to connect to the remote image service by
|
||||
|
@ -31,14 +31,16 @@ import (
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
"k8s.io/component-base/logs/logreduction"
|
||||
tracing "k8s.io/component-base/tracing"
|
||||
internalapi "k8s.io/cri-api/pkg/apis"
|
||||
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
|
||||
"k8s.io/cri-client/pkg/util"
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
utilexec "k8s.io/utils/exec"
|
||||
|
||||
"k8s.io/cri-client/pkg/internal"
|
||||
"k8s.io/cri-client/pkg/util"
|
||||
)
|
||||
|
||||
// remoteRuntimeService is a gRPC implementation of internalapi.RuntimeService.
|
||||
@ -79,7 +81,7 @@ const (
|
||||
|
||||
// NewRemoteRuntimeService creates a new internalapi.RuntimeService.
|
||||
func NewRemoteRuntimeService(endpoint string, connectionTimeout time.Duration, tp trace.TracerProvider, logger *klog.Logger) (internalapi.RuntimeService, error) {
|
||||
log(logger, 3, "Connecting to runtime service", "endpoint", endpoint)
|
||||
internal.Log(logger, 3, "Connecting to runtime service", "endpoint", endpoint)
|
||||
addr, dialer, err := util.GetAddressAndDialer(endpoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -118,7 +120,7 @@ func NewRemoteRuntimeService(endpoint string, connectionTimeout time.Duration, t
|
||||
|
||||
conn, err := grpc.DialContext(ctx, addr, dialOpts...)
|
||||
if err != nil {
|
||||
logErr(logger, err, "Connect remote runtime failed", "address", addr)
|
||||
internal.LogErr(logger, err, "Connect remote runtime failed", "address", addr)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -136,11 +138,11 @@ func NewRemoteRuntimeService(endpoint string, connectionTimeout time.Duration, t
|
||||
}
|
||||
|
||||
func (r *remoteRuntimeService) log(level int, msg string, keyAndValues ...any) {
|
||||
log(r.logger, level, msg, keyAndValues...)
|
||||
internal.Log(r.logger, level, msg, keyAndValues...)
|
||||
}
|
||||
|
||||
func (r *remoteRuntimeService) logErr(err error, msg string, keyAndValues ...any) {
|
||||
logErr(r.logger, err, msg, keyAndValues...)
|
||||
internal.LogErr(r.logger, err, msg, keyAndValues...)
|
||||
}
|
||||
|
||||
// validateServiceConnection tries to connect to the remote runtime service by
|
||||
|
@ -20,7 +20,6 @@ import (
|
||||
"fmt"
|
||||
|
||||
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
// maxMsgSize use 16MB as the default message size limit.
|
||||
@ -78,17 +77,3 @@ func verifyContainerStatus(status *runtimeapi.ContainerStatus) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func log(logger *klog.Logger, level int, msg string, keyAndValues ...any) {
|
||||
if logger == nil {
|
||||
return
|
||||
}
|
||||
logger.V(level).Info(msg, keyAndValues...)
|
||||
}
|
||||
|
||||
func logErr(logger *klog.Logger, err error, msg string, keyAndValues ...any) {
|
||||
if logger == nil {
|
||||
return
|
||||
}
|
||||
logger.Error(err, msg, keyAndValues...)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user