mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 03:41:45 +00:00
Merge pull request #104873 from pohly/json-output-stream
JSON output streams
This commit is contained in:
commit
fb82a0d7eb
@ -188,6 +188,14 @@ var (
|
||||
"HealthzBindAddress",
|
||||
"HealthzPort",
|
||||
"Logging.Format",
|
||||
"Logging.Options.JSON.InfoBufferSize.Quantity.Format",
|
||||
"Logging.Options.JSON.InfoBufferSize.Quantity.d.Dec.scale",
|
||||
"Logging.Options.JSON.InfoBufferSize.Quantity.d.Dec.unscaled.abs[*]",
|
||||
"Logging.Options.JSON.InfoBufferSize.Quantity.d.Dec.unscaled.neg",
|
||||
"Logging.Options.JSON.InfoBufferSize.Quantity.i.scale",
|
||||
"Logging.Options.JSON.InfoBufferSize.Quantity.i.value",
|
||||
"Logging.Options.JSON.InfoBufferSize.Quantity.s",
|
||||
"Logging.Options.JSON.SplitStream",
|
||||
"Logging.Sanitization",
|
||||
"TLSCipherSuites[*]",
|
||||
"TLSMinVersion",
|
||||
|
@ -54,6 +54,9 @@ kubeAPIBurst: 10
|
||||
kubeAPIQPS: 5
|
||||
logging:
|
||||
format: text
|
||||
options:
|
||||
json:
|
||||
infoBufferSize: "0"
|
||||
makeIPTablesUtilChains: true
|
||||
maxOpenFiles: 1000000
|
||||
maxPods: 110
|
||||
|
@ -54,6 +54,9 @@ kubeAPIBurst: 10
|
||||
kubeAPIQPS: 5
|
||||
logging:
|
||||
format: text
|
||||
options:
|
||||
json:
|
||||
infoBufferSize: "0"
|
||||
makeIPTablesUtilChains: true
|
||||
maxOpenFiles: 1000000
|
||||
maxPods: 110
|
||||
|
2
pkg/kubelet/apis/config/zz_generated.deepcopy.go
generated
2
pkg/kubelet/apis/config/zz_generated.deepcopy.go
generated
@ -280,7 +280,7 @@ func (in *KubeletConfiguration) DeepCopyInto(out *KubeletConfiguration) {
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
out.Logging = in.Logging
|
||||
in.Logging.DeepCopyInto(&out.Logging)
|
||||
out.ShutdownGracePeriod = in.ShutdownGracePeriod
|
||||
out.ShutdownGracePeriodCriticalPods = in.ShutdownGracePeriodCriticalPods
|
||||
if in.ReservedMemory != nil {
|
||||
|
@ -61,8 +61,32 @@ func (m *Quantity) XXX_DiscardUnknown() {
|
||||
|
||||
var xxx_messageInfo_Quantity proto.InternalMessageInfo
|
||||
|
||||
func (m *QuantityValue) Reset() { *m = QuantityValue{} }
|
||||
func (*QuantityValue) ProtoMessage() {}
|
||||
func (*QuantityValue) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_612bba87bd70906c, []int{1}
|
||||
}
|
||||
func (m *QuantityValue) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_QuantityValue.Unmarshal(m, b)
|
||||
}
|
||||
func (m *QuantityValue) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_QuantityValue.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *QuantityValue) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_QuantityValue.Merge(m, src)
|
||||
}
|
||||
func (m *QuantityValue) XXX_Size() int {
|
||||
return xxx_messageInfo_QuantityValue.Size(m)
|
||||
}
|
||||
func (m *QuantityValue) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_QuantityValue.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_QuantityValue proto.InternalMessageInfo
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*Quantity)(nil), "k8s.io.apimachinery.pkg.api.resource.Quantity")
|
||||
proto.RegisterType((*QuantityValue)(nil), "k8s.io.apimachinery.pkg.api.resource.QuantityValue")
|
||||
}
|
||||
|
||||
func init() {
|
||||
@ -70,20 +94,21 @@ func init() {
|
||||
}
|
||||
|
||||
var fileDescriptor_612bba87bd70906c = []byte{
|
||||
// 237 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x4c, 0x8e, 0xb1, 0x4e, 0xc3, 0x30,
|
||||
0x10, 0x40, 0xcf, 0x0b, 0x2a, 0x19, 0x2b, 0x84, 0x10, 0xc3, 0xa5, 0x42, 0x0c, 0x2c, 0xd8, 0x6b,
|
||||
0xc5, 0xc8, 0xce, 0x00, 0x23, 0x5b, 0x92, 0x1e, 0xae, 0x15, 0xd5, 0x8e, 0x2e, 0x36, 0x52, 0xb7,
|
||||
0x8e, 0x8c, 0x1d, 0x19, 0x9b, 0xbf, 0xe9, 0xd8, 0xb1, 0x03, 0x03, 0x31, 0x3f, 0x82, 0xea, 0x36,
|
||||
0x52, 0xb7, 0x7b, 0xef, 0xf4, 0x4e, 0x97, 0xbd, 0xd4, 0xd3, 0x56, 0x1a, 0xa7, 0xea, 0x50, 0x12,
|
||||
0x5b, 0xf2, 0xd4, 0xaa, 0x4f, 0xb2, 0x33, 0xc7, 0xea, 0xb4, 0x28, 0x1a, 0xb3, 0x28, 0xaa, 0xb9,
|
||||
0xb1, 0xc4, 0x4b, 0xd5, 0xd4, 0xfa, 0x20, 0x14, 0x53, 0xeb, 0x02, 0x57, 0xa4, 0x34, 0x59, 0xe2,
|
||||
0xc2, 0xd3, 0x4c, 0x36, 0xec, 0xbc, 0x1b, 0xdf, 0x1f, 0x2b, 0x79, 0x5e, 0xc9, 0xa6, 0xd6, 0x07,
|
||||
0x21, 0x87, 0xea, 0xf6, 0x51, 0x1b, 0x3f, 0x0f, 0xa5, 0xac, 0xdc, 0x42, 0x69, 0xa7, 0x9d, 0x4a,
|
||||
0x71, 0x19, 0x3e, 0x12, 0x25, 0x48, 0xd3, 0xf1, 0xe8, 0xdd, 0x34, 0x1b, 0xbd, 0x86, 0xc2, 0x7a,
|
||||
0xe3, 0x97, 0xe3, 0xeb, 0xec, 0xa2, 0xf5, 0x6c, 0xac, 0xbe, 0x11, 0x13, 0xf1, 0x70, 0xf9, 0x76,
|
||||
0xa2, 0xa7, 0xab, 0xef, 0x4d, 0x0e, 0x5f, 0x5d, 0x0e, 0xeb, 0x2e, 0x87, 0x4d, 0x97, 0xc3, 0xea,
|
||||
0x67, 0x02, 0xcf, 0x72, 0xdb, 0x23, 0xec, 0x7a, 0x84, 0x7d, 0x8f, 0xb0, 0x8a, 0x28, 0xb6, 0x11,
|
||||
0xc5, 0x2e, 0xa2, 0xd8, 0x47, 0x14, 0xbf, 0x11, 0xc5, 0xfa, 0x0f, 0xe1, 0x7d, 0x34, 0x3c, 0xf6,
|
||||
0x1f, 0x00, 0x00, 0xff, 0xff, 0x3c, 0x08, 0x88, 0x49, 0x0e, 0x01, 0x00, 0x00,
|
||||
// 254 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xf2, 0xcd, 0xb6, 0x28, 0xd6,
|
||||
0xcb, 0xcc, 0xd7, 0xcf, 0x2e, 0x4d, 0x4a, 0x2d, 0xca, 0x4b, 0x2d, 0x49, 0x2d, 0xd6, 0x2f, 0x4b,
|
||||
0xcd, 0x4b, 0xc9, 0x2f, 0xd2, 0x87, 0x4a, 0x24, 0x16, 0x64, 0xe6, 0x26, 0x26, 0x67, 0x64, 0xe6,
|
||||
0xa5, 0x16, 0x55, 0xea, 0x17, 0x64, 0xa7, 0x83, 0x04, 0xf4, 0x8b, 0x52, 0x8b, 0xf3, 0x4b, 0x8b,
|
||||
0x92, 0x53, 0xf5, 0xd3, 0x53, 0xf3, 0x52, 0x8b, 0x12, 0x4b, 0x52, 0x53, 0xf4, 0x0a, 0x8a, 0xf2,
|
||||
0x4b, 0xf2, 0x85, 0x54, 0x20, 0xba, 0xf4, 0x90, 0x75, 0xe9, 0x15, 0x64, 0xa7, 0x83, 0x04, 0xf4,
|
||||
0x60, 0xba, 0xa4, 0x74, 0xd3, 0x33, 0x4b, 0x32, 0x4a, 0x93, 0xf4, 0x92, 0xf3, 0x73, 0xf5, 0xd3,
|
||||
0xf3, 0xd3, 0xf3, 0xf5, 0xc1, 0x9a, 0x93, 0x4a, 0xd3, 0xc0, 0x3c, 0x30, 0x07, 0xcc, 0x82, 0x18,
|
||||
0xaa, 0x64, 0xc1, 0xc5, 0x11, 0x58, 0x9a, 0x98, 0x57, 0x92, 0x59, 0x52, 0x29, 0x24, 0xc6, 0xc5,
|
||||
0x56, 0x5c, 0x52, 0x94, 0x99, 0x97, 0x2e, 0xc1, 0xa8, 0xc0, 0xa8, 0xc1, 0x19, 0x04, 0xe5, 0x59,
|
||||
0x89, 0xcc, 0x58, 0x20, 0xcf, 0xd0, 0xb1, 0x50, 0x9e, 0x61, 0xc2, 0x42, 0x79, 0x86, 0x05, 0x0b,
|
||||
0xe5, 0x19, 0x1a, 0xee, 0x28, 0x30, 0x28, 0xd9, 0x72, 0xf1, 0xc2, 0x74, 0x86, 0x25, 0xe6, 0x94,
|
||||
0xa6, 0x92, 0xa6, 0xdd, 0x49, 0xef, 0xc4, 0x43, 0x39, 0x86, 0x0b, 0x0f, 0xe5, 0x18, 0x6e, 0x3c,
|
||||
0x94, 0x63, 0x68, 0x78, 0x24, 0xc7, 0x78, 0xe2, 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x37,
|
||||
0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, 0x38, 0xe1, 0xb1, 0x1c, 0x43, 0x14, 0x07, 0xcc, 0x5f,
|
||||
0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x21, 0x76, 0x9f, 0x66, 0x4d, 0x01, 0x00, 0x00,
|
||||
}
|
||||
|
@ -86,3 +86,15 @@ message Quantity {
|
||||
optional string string = 1;
|
||||
}
|
||||
|
||||
// QuantityValue makes it possible to use a Quantity as value for a command
|
||||
// line parameter.
|
||||
//
|
||||
// +protobuf=true
|
||||
// +protobuf.embed=string
|
||||
// +protobuf.options.marshal=false
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
// +k8s:deepcopy-gen=true
|
||||
message QuantityValue {
|
||||
optional string string = 1;
|
||||
}
|
||||
|
||||
|
@ -764,3 +764,30 @@ func (q *Quantity) SetScaled(value int64, scale Scale) {
|
||||
q.d.Dec = nil
|
||||
q.i = int64Amount{value: value, scale: scale}
|
||||
}
|
||||
|
||||
// QuantityValue makes it possible to use a Quantity as value for a command
|
||||
// line parameter.
|
||||
//
|
||||
// +protobuf=true
|
||||
// +protobuf.embed=string
|
||||
// +protobuf.options.marshal=false
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
// +k8s:deepcopy-gen=true
|
||||
type QuantityValue struct {
|
||||
Quantity
|
||||
}
|
||||
|
||||
// Set implements pflag.Value.Set and Go flag.Value.Set.
|
||||
func (q *QuantityValue) Set(s string) error {
|
||||
quantity, err := ParseQuantity(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
q.Quantity = quantity
|
||||
return nil
|
||||
}
|
||||
|
||||
// Type implements pflag.Value.Type.
|
||||
func (q QuantityValue) Type() string {
|
||||
return "quantity"
|
||||
}
|
||||
|
@ -21,11 +21,13 @@ import (
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"unicode"
|
||||
|
||||
fuzz "github.com/google/gofuzz"
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
inf "gopkg.in/inf.v0"
|
||||
)
|
||||
@ -1475,3 +1477,42 @@ func BenchmarkQuantityAsApproximateFloat64(b *testing.B) {
|
||||
}
|
||||
b.StopTimer()
|
||||
}
|
||||
|
||||
var _ pflag.Value = &QuantityValue{}
|
||||
|
||||
func TestQuantityValueSet(t *testing.T) {
|
||||
q := QuantityValue{}
|
||||
|
||||
if err := q.Set("invalid"); err == nil {
|
||||
|
||||
t.Error("'invalid' did not trigger a parse error")
|
||||
}
|
||||
|
||||
if err := q.Set("1Mi"); err != nil {
|
||||
t.Errorf("parsing 1Mi should have worked, got: %v", err)
|
||||
}
|
||||
if q.Value() != 1024*1024 {
|
||||
t.Errorf("quantity should have been set to 1Mi, got: %v", q)
|
||||
}
|
||||
|
||||
data, err := json.Marshal(q)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected encoding error: %v", err)
|
||||
}
|
||||
expected := `"1Mi"`
|
||||
if string(data) != expected {
|
||||
t.Errorf("expected 1Mi value to be encoded as %q, got: %q", expected, string(data))
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleQuantityValue() {
|
||||
q := QuantityValue{
|
||||
Quantity: MustParse("1Mi"),
|
||||
}
|
||||
fs := pflag.FlagSet{}
|
||||
fs.SetOutput(os.Stdout)
|
||||
fs.Var(&q, "mem", "sets amount of memory")
|
||||
fs.PrintDefaults()
|
||||
// Output:
|
||||
// --mem quantity sets amount of memory (default 1Mi)
|
||||
}
|
||||
|
@ -26,3 +26,20 @@ func (in *Quantity) DeepCopyInto(out *Quantity) {
|
||||
*out = in.DeepCopy()
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *QuantityValue) DeepCopyInto(out *QuantityValue) {
|
||||
*out = *in
|
||||
out.Quantity = in.Quantity.DeepCopy()
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new QuantityValue.
|
||||
func (in *QuantityValue) DeepCopy() *QuantityValue {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(QuantityValue)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
||||
package config
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
@ -88,4 +89,25 @@ type LoggingConfiguration struct {
|
||||
// [Experimental] When enabled prevents logging of fields tagged as sensitive (passwords, keys, tokens).
|
||||
// Runtime log sanitization may introduce significant computation overhead and therefore should not be enabled in production.`)
|
||||
Sanitization bool
|
||||
// [Experimental] Options holds additional parameters that are specific
|
||||
// to the different logging formats. Only the options for the selected
|
||||
// format get used, but all of them get validated.
|
||||
Options FormatOptions
|
||||
}
|
||||
|
||||
// FormatOptions contains options for the different logging formats.
|
||||
type FormatOptions struct {
|
||||
// [Experimental] JSON contains options for logging format "json".
|
||||
JSON JSONOptions
|
||||
}
|
||||
|
||||
// JSONOptions contains options for logging format "json".
|
||||
type JSONOptions struct {
|
||||
// [Experimental] SplitStream redirects error messages to stderr while
|
||||
// info messages go to stdout, with buffering. The default is to write
|
||||
// both to stdout, without buffering.
|
||||
SplitStream bool
|
||||
// [Experimental] InfoBufferSize sets the size of the info stream when
|
||||
// using split streams. The default is zero, which disables buffering.
|
||||
InfoBufferSize resource.QuantityValue
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ package v1alpha1
|
||||
import (
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
utilpointer "k8s.io/utils/pointer"
|
||||
)
|
||||
@ -110,4 +111,15 @@ func RecommendedLoggingConfiguration(obj *LoggingConfiguration) {
|
||||
if obj.Format == "" {
|
||||
obj.Format = "text"
|
||||
}
|
||||
var empty resource.QuantityValue
|
||||
if obj.Options.JSON.InfoBufferSize == empty {
|
||||
obj.Options.JSON.InfoBufferSize = resource.QuantityValue{
|
||||
// This is similar, but not quite the same as a default
|
||||
// constructed instance.
|
||||
Quantity: *resource.NewQuantity(0, resource.DecimalSI),
|
||||
}
|
||||
// This sets the unexported Quantity.s which will be compared
|
||||
// by reflect.DeepEqual in some tests.
|
||||
_ = obj.Options.JSON.InfoBufferSize.String()
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
@ -90,4 +91,25 @@ type LoggingConfiguration struct {
|
||||
// [Experimental] When enabled prevents logging of fields tagged as sensitive (passwords, keys, tokens).
|
||||
// Runtime log sanitization may introduce significant computation overhead and therefore should not be enabled in production.`)
|
||||
Sanitization bool `json:"sanitization,omitempty"`
|
||||
// [Experimental] Options holds additional parameters that are specific
|
||||
// to the different logging formats. Only the options for the selected
|
||||
// format get used, but all of them get validated.
|
||||
Options FormatOptions `json:"options,omitempty"`
|
||||
}
|
||||
|
||||
// FormatOptions contains options for the different logging formats.
|
||||
type FormatOptions struct {
|
||||
// [Experimental] JSON contains options for logging format "json".
|
||||
JSON JSONOptions `json:"json,omitempty"`
|
||||
}
|
||||
|
||||
// JSONOptions contains options for logging format "json".
|
||||
type JSONOptions struct {
|
||||
// [Experimental] SplitStream redirects error messages to stderr while
|
||||
// info messages go to stdout, with buffering. The default is to write
|
||||
// both to stdout, without buffering.
|
||||
SplitStream bool `json:"splitStream,omitempty"`
|
||||
// [Experimental] InfoBufferSize sets the size of the info stream when
|
||||
// using split streams. The default is zero, which disables buffering.
|
||||
InfoBufferSize resource.QuantityValue `json:"infoBufferSize,omitempty"`
|
||||
}
|
||||
|
@ -35,6 +35,26 @@ func init() {
|
||||
// RegisterConversions adds conversion functions to the given scheme.
|
||||
// Public to allow building arbitrary schemes.
|
||||
func RegisterConversions(s *runtime.Scheme) error {
|
||||
if err := s.AddGeneratedConversionFunc((*FormatOptions)(nil), (*config.FormatOptions)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1alpha1_FormatOptions_To_config_FormatOptions(a.(*FormatOptions), b.(*config.FormatOptions), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*config.FormatOptions)(nil), (*FormatOptions)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_config_FormatOptions_To_v1alpha1_FormatOptions(a.(*config.FormatOptions), b.(*FormatOptions), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*JSONOptions)(nil), (*config.JSONOptions)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1alpha1_JSONOptions_To_config_JSONOptions(a.(*JSONOptions), b.(*config.JSONOptions), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*config.JSONOptions)(nil), (*JSONOptions)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_config_JSONOptions_To_v1alpha1_JSONOptions(a.(*config.JSONOptions), b.(*JSONOptions), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddConversionFunc((*config.ClientConnectionConfiguration)(nil), (*ClientConnectionConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_config_ClientConnectionConfiguration_To_v1alpha1_ClientConnectionConfiguration(a.(*config.ClientConnectionConfiguration), b.(*ClientConnectionConfiguration), scope)
|
||||
}); err != nil {
|
||||
@ -116,6 +136,52 @@ func autoConvert_config_DebuggingConfiguration_To_v1alpha1_DebuggingConfiguratio
|
||||
return nil
|
||||
}
|
||||
|
||||
func autoConvert_v1alpha1_FormatOptions_To_config_FormatOptions(in *FormatOptions, out *config.FormatOptions, s conversion.Scope) error {
|
||||
if err := Convert_v1alpha1_JSONOptions_To_config_JSONOptions(&in.JSON, &out.JSON, s); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1alpha1_FormatOptions_To_config_FormatOptions is an autogenerated conversion function.
|
||||
func Convert_v1alpha1_FormatOptions_To_config_FormatOptions(in *FormatOptions, out *config.FormatOptions, s conversion.Scope) error {
|
||||
return autoConvert_v1alpha1_FormatOptions_To_config_FormatOptions(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_config_FormatOptions_To_v1alpha1_FormatOptions(in *config.FormatOptions, out *FormatOptions, s conversion.Scope) error {
|
||||
if err := Convert_config_JSONOptions_To_v1alpha1_JSONOptions(&in.JSON, &out.JSON, s); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_config_FormatOptions_To_v1alpha1_FormatOptions is an autogenerated conversion function.
|
||||
func Convert_config_FormatOptions_To_v1alpha1_FormatOptions(in *config.FormatOptions, out *FormatOptions, s conversion.Scope) error {
|
||||
return autoConvert_config_FormatOptions_To_v1alpha1_FormatOptions(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1alpha1_JSONOptions_To_config_JSONOptions(in *JSONOptions, out *config.JSONOptions, s conversion.Scope) error {
|
||||
out.SplitStream = in.SplitStream
|
||||
out.InfoBufferSize = in.InfoBufferSize
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1alpha1_JSONOptions_To_config_JSONOptions is an autogenerated conversion function.
|
||||
func Convert_v1alpha1_JSONOptions_To_config_JSONOptions(in *JSONOptions, out *config.JSONOptions, s conversion.Scope) error {
|
||||
return autoConvert_v1alpha1_JSONOptions_To_config_JSONOptions(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_config_JSONOptions_To_v1alpha1_JSONOptions(in *config.JSONOptions, out *JSONOptions, s conversion.Scope) error {
|
||||
out.SplitStream = in.SplitStream
|
||||
out.InfoBufferSize = in.InfoBufferSize
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_config_JSONOptions_To_v1alpha1_JSONOptions is an autogenerated conversion function.
|
||||
func Convert_config_JSONOptions_To_v1alpha1_JSONOptions(in *config.JSONOptions, out *JSONOptions, s conversion.Scope) error {
|
||||
return autoConvert_config_JSONOptions_To_v1alpha1_JSONOptions(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1alpha1_LeaderElectionConfiguration_To_config_LeaderElectionConfiguration(in *LeaderElectionConfiguration, out *config.LeaderElectionConfiguration, s conversion.Scope) error {
|
||||
if err := v1.Convert_Pointer_bool_To_bool(&in.LeaderElect, &out.LeaderElect, s); err != nil {
|
||||
return err
|
||||
@ -145,11 +211,17 @@ func autoConvert_config_LeaderElectionConfiguration_To_v1alpha1_LeaderElectionCo
|
||||
func autoConvert_v1alpha1_LoggingConfiguration_To_config_LoggingConfiguration(in *LoggingConfiguration, out *config.LoggingConfiguration, s conversion.Scope) error {
|
||||
out.Format = in.Format
|
||||
out.Sanitization = in.Sanitization
|
||||
if err := Convert_v1alpha1_FormatOptions_To_config_FormatOptions(&in.Options, &out.Options, s); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func autoConvert_config_LoggingConfiguration_To_v1alpha1_LoggingConfiguration(in *config.LoggingConfiguration, out *LoggingConfiguration, s conversion.Scope) error {
|
||||
out.Format = in.Format
|
||||
out.Sanitization = in.Sanitization
|
||||
if err := Convert_config_FormatOptions_To_v1alpha1_FormatOptions(&in.Options, &out.Options, s); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -63,6 +63,40 @@ func (in *DebuggingConfiguration) DeepCopy() *DebuggingConfiguration {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *FormatOptions) DeepCopyInto(out *FormatOptions) {
|
||||
*out = *in
|
||||
in.JSON.DeepCopyInto(&out.JSON)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FormatOptions.
|
||||
func (in *FormatOptions) DeepCopy() *FormatOptions {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(FormatOptions)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JSONOptions) DeepCopyInto(out *JSONOptions) {
|
||||
*out = *in
|
||||
in.InfoBufferSize.DeepCopyInto(&out.InfoBufferSize)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JSONOptions.
|
||||
func (in *JSONOptions) DeepCopy() *JSONOptions {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JSONOptions)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *LeaderElectionConfiguration) DeepCopyInto(out *LeaderElectionConfiguration) {
|
||||
*out = *in
|
||||
@ -90,6 +124,7 @@ func (in *LeaderElectionConfiguration) DeepCopy() *LeaderElectionConfiguration {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *LoggingConfiguration) DeepCopyInto(out *LoggingConfiguration) {
|
||||
*out = *in
|
||||
in.Options.DeepCopyInto(&out.Options)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -53,6 +53,40 @@ func (in *DebuggingConfiguration) DeepCopy() *DebuggingConfiguration {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *FormatOptions) DeepCopyInto(out *FormatOptions) {
|
||||
*out = *in
|
||||
in.JSON.DeepCopyInto(&out.JSON)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FormatOptions.
|
||||
func (in *FormatOptions) DeepCopy() *FormatOptions {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(FormatOptions)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JSONOptions) DeepCopyInto(out *JSONOptions) {
|
||||
*out = *in
|
||||
in.InfoBufferSize.DeepCopyInto(&out.InfoBufferSize)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JSONOptions.
|
||||
func (in *JSONOptions) DeepCopy() *JSONOptions {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JSONOptions)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *LeaderElectionConfiguration) DeepCopyInto(out *LeaderElectionConfiguration) {
|
||||
*out = *in
|
||||
@ -75,6 +109,7 @@ func (in *LeaderElectionConfiguration) DeepCopy() *LeaderElectionConfiguration {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *LoggingConfiguration) DeepCopyInto(out *LoggingConfiguration) {
|
||||
*out = *in
|
||||
in.Options.DeepCopyInto(&out.Options)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -67,6 +67,13 @@ func BindLoggingFlags(c *config.LoggingConfiguration, fs *pflag.FlagSet) {
|
||||
registry.LogRegistry.Freeze()
|
||||
fs.BoolVar(&c.Sanitization, "experimental-logging-sanitization", c.Sanitization, `[Experimental] When enabled prevents logging of fields tagged as sensitive (passwords, keys, tokens).
|
||||
Runtime log sanitization may introduce significant computation overhead and therefore should not be enabled in production.`)
|
||||
|
||||
// JSON options. We only register them if "json" is a valid format. The
|
||||
// config file API however always has them.
|
||||
if _, err := registry.LogRegistry.Get("json"); err == nil {
|
||||
fs.BoolVar(&c.Options.JSON.SplitStream, "log-json-split-stream", false, "[Experimental] In JSON format, write error messages to stderr and info messages to stdout. The default is to write a single stream to stdout.")
|
||||
fs.Var(&c.Options.JSON.InfoBufferSize, "log-json-info-buffer-size", "[Experimental] In JSON format with split output streams, the info messages can be buffered for a while to increase performance. The default value of zero bytes disables buffering. The size can be specified as number of bytes (512), multiples of 1000 (1K), multiples of 1024 (2Ki), or powers of those (3M, 4G, 5Mi, 6Gi).")
|
||||
}
|
||||
}
|
||||
|
||||
// UnsupportedLoggingFlags lists unsupported logging flags. The normalize
|
||||
|
@ -25,6 +25,7 @@ import (
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
|
||||
"k8s.io/component-base/config"
|
||||
"k8s.io/component-base/logs/registry"
|
||||
)
|
||||
|
||||
@ -33,15 +34,41 @@ var (
|
||||
timeNow = time.Now
|
||||
)
|
||||
|
||||
// NewJSONLogger creates a new json logr.Logger using the given Zap Logger to log.
|
||||
func NewJSONLogger(w zapcore.WriteSyncer) logr.Logger {
|
||||
// NewJSONLogger creates a new json logr.Logger and its associated
|
||||
// flush function. The separate error stream is optional and may be nil.
|
||||
func NewJSONLogger(infoStream, errorStream zapcore.WriteSyncer) (logr.Logger, func()) {
|
||||
encoder := zapcore.NewJSONEncoder(encoderConfig)
|
||||
// The log level intentionally gets set as low as possible to
|
||||
// ensure that all messages are printed when this logger gets
|
||||
// called by klog. The actual verbosity check happens in klog.
|
||||
core := zapcore.NewCore(encoder, zapcore.AddSync(w), zapcore.Level(-127))
|
||||
var core zapcore.Core
|
||||
if errorStream == nil {
|
||||
core = zapcore.NewCore(encoder, zapcore.AddSync(infoStream), zapcore.Level(-127))
|
||||
} else {
|
||||
// Set up writing of error messages to stderr and info messages
|
||||
// to stdout. Info messages get optionally buffered and flushed
|
||||
// - through klog.FlushLogs -> zapr Flush -> zap Sync
|
||||
// - when an error gets logged
|
||||
//
|
||||
// The later is important when both streams get merged into a single
|
||||
// stream by the consumer (same console for a command line tool, pod
|
||||
// log for a container) because without it, messages get reordered.
|
||||
flushError := writeWithFlushing{
|
||||
WriteSyncer: errorStream,
|
||||
other: infoStream,
|
||||
}
|
||||
highPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
|
||||
return lvl >= zapcore.ErrorLevel
|
||||
})
|
||||
lowPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
|
||||
return lvl < zapcore.ErrorLevel
|
||||
})
|
||||
core = zapcore.NewTee(
|
||||
zapcore.NewCore(encoder, flushError, highPriority),
|
||||
zapcore.NewCore(encoder, infoStream, lowPriority),
|
||||
)
|
||||
}
|
||||
l := zap.New(core, zap.WithCaller(true))
|
||||
return zapr.NewLoggerWithOptions(l, zapr.LogInfoLevel("v"), zapr.ErrorKey("err"))
|
||||
return zapr.NewLoggerWithOptions(l, zapr.LogInfoLevel("v"), zapr.ErrorKey("err")), func() {
|
||||
l.Sync()
|
||||
}
|
||||
}
|
||||
|
||||
var encoderConfig = zapcore.EncoderConfig{
|
||||
@ -62,8 +89,36 @@ func epochMillisTimeEncoder(_ time.Time, enc zapcore.PrimitiveArrayEncoder) {
|
||||
// Factory produces JSON logger instances.
|
||||
type Factory struct{}
|
||||
|
||||
func (f Factory) Create() logr.Logger {
|
||||
return NewJSONLogger(zapcore.Lock(os.Stdout))
|
||||
var _ registry.LogFormatFactory = Factory{}
|
||||
|
||||
func (f Factory) Create(options config.FormatOptions) (logr.Logger, func()) {
|
||||
if options.JSON.SplitStream {
|
||||
infoStream := zapcore.Lock(os.Stdout)
|
||||
size := options.JSON.InfoBufferSize.Value()
|
||||
if size > 0 {
|
||||
// Prevent integer overflow.
|
||||
if size > 2*1024*1024*1024 {
|
||||
size = 2 * 1024 * 1024 * 1024
|
||||
}
|
||||
infoStream = &zapcore.BufferedWriteSyncer{
|
||||
WS: infoStream,
|
||||
Size: int(size),
|
||||
}
|
||||
}
|
||||
return NewJSONLogger(infoStream, zapcore.Lock(os.Stderr))
|
||||
}
|
||||
out := zapcore.Lock(os.Stdout)
|
||||
return NewJSONLogger(out, out)
|
||||
}
|
||||
|
||||
var _ registry.LogFormatFactory = Factory{}
|
||||
// writeWithFlushing is a wrapper around an output stream which flushes another
|
||||
// output stream before each write.
|
||||
type writeWithFlushing struct {
|
||||
zapcore.WriteSyncer
|
||||
other zapcore.WriteSyncer
|
||||
}
|
||||
|
||||
func (f writeWithFlushing) Write(bs []byte) (int, error) {
|
||||
f.other.Sync()
|
||||
return f.WriteSyncer.Write(bs)
|
||||
}
|
||||
|
@ -23,8 +23,10 @@ import (
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
var writer = zapcore.AddSync(&writeSyncer{})
|
||||
|
||||
func BenchmarkInfoLoggerInfo(b *testing.B) {
|
||||
logger := NewJSONLogger(zapcore.AddSync(&writeSyncer{}))
|
||||
logger, _ := NewJSONLogger(writer, writer)
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
@ -53,7 +55,7 @@ func BenchmarkInfoLoggerInfo(b *testing.B) {
|
||||
}
|
||||
|
||||
func BenchmarkZapLoggerError(b *testing.B) {
|
||||
logger := NewJSONLogger(zapcore.AddSync(&writeSyncer{}))
|
||||
logger, _ := NewJSONLogger(writer, writer)
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
@ -83,7 +85,7 @@ func BenchmarkZapLoggerError(b *testing.B) {
|
||||
}
|
||||
|
||||
func BenchmarkZapLoggerV(b *testing.B) {
|
||||
logger := NewJSONLogger(zapcore.AddSync(&writeSyncer{}))
|
||||
logger, _ := NewJSONLogger(writer, writer)
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
|
@ -17,7 +17,6 @@ limitations under the License.
|
||||
package logs
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
@ -64,10 +63,9 @@ func TestZapLoggerInfo(t *testing.T) {
|
||||
|
||||
for _, data := range testDataInfo {
|
||||
var buffer bytes.Buffer
|
||||
writer := bufio.NewWriter(&buffer)
|
||||
var sampleInfoLogger = NewJSONLogger(zapcore.AddSync(writer))
|
||||
writer := zapcore.AddSync(&buffer)
|
||||
sampleInfoLogger, _ := NewJSONLogger(writer, nil)
|
||||
sampleInfoLogger.Info(data.msg, data.keysValues...)
|
||||
writer.Flush()
|
||||
logStr := buffer.String()
|
||||
|
||||
logStrLines := strings.Split(logStr, "\n")
|
||||
@ -96,7 +94,7 @@ func TestZapLoggerInfo(t *testing.T) {
|
||||
|
||||
// TestZapLoggerEnabled test ZapLogger enabled
|
||||
func TestZapLoggerEnabled(t *testing.T) {
|
||||
var sampleInfoLogger = NewJSONLogger(nil)
|
||||
sampleInfoLogger, _ := NewJSONLogger(nil, nil)
|
||||
for i := 0; i < 11; i++ {
|
||||
if !sampleInfoLogger.V(i).Enabled() {
|
||||
t.Errorf("V(%d).Info should be enabled", i)
|
||||
@ -112,10 +110,9 @@ func TestZapLoggerV(t *testing.T) {
|
||||
|
||||
for i := 0; i < 11; i++ {
|
||||
var buffer bytes.Buffer
|
||||
writer := bufio.NewWriter(&buffer)
|
||||
var sampleInfoLogger = NewJSONLogger(zapcore.AddSync(writer))
|
||||
writer := zapcore.AddSync(&buffer)
|
||||
sampleInfoLogger, _ := NewJSONLogger(writer, nil)
|
||||
sampleInfoLogger.V(i).Info("test", "ns", "default", "podnum", 2, "time", time.Microsecond)
|
||||
writer.Flush()
|
||||
logStr := buffer.String()
|
||||
var v, lineNo int
|
||||
expectFormat := "{\"ts\":0.000123,\"caller\":\"json/json_test.go:%d\",\"msg\":\"test\",\"v\":%d,\"ns\":\"default\",\"podnum\":2,\"time\":\"1µs\"}\n"
|
||||
@ -137,13 +134,12 @@ func TestZapLoggerV(t *testing.T) {
|
||||
// TestZapLoggerError test ZapLogger json error format
|
||||
func TestZapLoggerError(t *testing.T) {
|
||||
var buffer bytes.Buffer
|
||||
writer := bufio.NewWriter(&buffer)
|
||||
writer := zapcore.AddSync(&buffer)
|
||||
timeNow = func() time.Time {
|
||||
return time.Date(1970, time.January, 1, 0, 0, 0, 123, time.UTC)
|
||||
}
|
||||
var sampleInfoLogger = NewJSONLogger(zapcore.AddSync(writer))
|
||||
sampleInfoLogger, _ := NewJSONLogger(writer, nil)
|
||||
sampleInfoLogger.Error(fmt.Errorf("invalid namespace:%s", "default"), "wrong namespace", "ns", "default", "podnum", 2, "time", time.Microsecond)
|
||||
writer.Flush()
|
||||
logStr := buffer.String()
|
||||
var ts float64
|
||||
var lineNo int
|
||||
@ -158,6 +154,38 @@ func TestZapLoggerError(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestZapLoggerStreams(t *testing.T) {
|
||||
var infoBuffer, errorBuffer bytes.Buffer
|
||||
log, _ := NewJSONLogger(zapcore.AddSync(&infoBuffer), zapcore.AddSync(&errorBuffer))
|
||||
|
||||
log.Error(fmt.Errorf("some error"), "failed")
|
||||
log.Info("hello world")
|
||||
|
||||
logStr := errorBuffer.String()
|
||||
var ts float64
|
||||
var lineNo int
|
||||
expectFormat := `{"ts":%f,"caller":"json/json_test.go:%d","msg":"failed","err":"some error"}`
|
||||
n, err := fmt.Sscanf(logStr, expectFormat, &ts, &lineNo)
|
||||
if n != 2 || err != nil {
|
||||
t.Errorf("error log format error: %d elements, error %s:\n%s", n, err, logStr)
|
||||
}
|
||||
expect := fmt.Sprintf(expectFormat, ts, lineNo)
|
||||
if !assert.JSONEq(t, expect, logStr) {
|
||||
t.Errorf("error log has wrong format \n expect:%s\n got:%s", expect, logStr)
|
||||
}
|
||||
|
||||
logStr = infoBuffer.String()
|
||||
expectFormat = `{"ts":%f,"caller":"json/json_test.go:%d","msg":"hello world","v":0}`
|
||||
n, err = fmt.Sscanf(logStr, expectFormat, &ts, &lineNo)
|
||||
if n != 2 || err != nil {
|
||||
t.Errorf("info log format error: %d elements, error %s:\n%s", n, err, logStr)
|
||||
}
|
||||
expect = fmt.Sprintf(expectFormat, ts, lineNo)
|
||||
if !assert.JSONEq(t, expect, logStr) {
|
||||
t.Errorf("info has wrong format \n expect:%s\n got:%s", expect, logStr)
|
||||
}
|
||||
}
|
||||
|
||||
type testBuff struct {
|
||||
writeCount int
|
||||
}
|
||||
|
@ -206,7 +206,8 @@ func TestKlogIntegration(t *testing.T) {
|
||||
for _, tc := range tcs {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
var buffer bytes.Buffer
|
||||
var logger = NewJSONLogger(zapcore.AddSync(&buffer))
|
||||
writer := zapcore.AddSync(&buffer)
|
||||
logger, _ := NewJSONLogger(writer, writer)
|
||||
klog.SetLogger(logger)
|
||||
defer klog.ClearLogger()
|
||||
|
||||
@ -236,7 +237,8 @@ func TestKlogIntegration(t *testing.T) {
|
||||
// TestKlogV test klog -v(--verbose) func available with json logger
|
||||
func TestKlogV(t *testing.T) {
|
||||
var buffer testBuff
|
||||
logger := NewJSONLogger(&buffer)
|
||||
writer := zapcore.AddSync(&buffer)
|
||||
logger, _ := NewJSONLogger(writer, writer)
|
||||
klog.SetLogger(logger)
|
||||
defer klog.ClearLogger()
|
||||
fs := flag.FlagSet{}
|
||||
|
@ -23,6 +23,7 @@ import (
|
||||
"github.com/spf13/pflag"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/component-base/config"
|
||||
"k8s.io/component-base/logs"
|
||||
@ -42,6 +43,14 @@ func TestJSONFlag(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestJSONFormatRegister(t *testing.T) {
|
||||
defaultOptions := config.FormatOptions{
|
||||
JSON: config.JSONOptions{
|
||||
InfoBufferSize: resource.QuantityValue{
|
||||
Quantity: *resource.NewQuantity(0, resource.DecimalSI),
|
||||
},
|
||||
},
|
||||
}
|
||||
_ = defaultOptions.JSON.InfoBufferSize.String()
|
||||
testcases := []struct {
|
||||
name string
|
||||
args []string
|
||||
@ -53,7 +62,8 @@ func TestJSONFormatRegister(t *testing.T) {
|
||||
args: []string{"--logging-format=json"},
|
||||
want: &logs.Options{
|
||||
Config: config.LoggingConfiguration{
|
||||
Format: logs.JSONLogFormat,
|
||||
Format: logs.JSONLogFormat,
|
||||
Options: defaultOptions,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -62,7 +72,8 @@ func TestJSONFormatRegister(t *testing.T) {
|
||||
args: []string{"--logging-format=test"},
|
||||
want: &logs.Options{
|
||||
Config: config.LoggingConfiguration{
|
||||
Format: "test",
|
||||
Format: "test",
|
||||
Options: defaultOptions,
|
||||
},
|
||||
},
|
||||
errs: field.ErrorList{&field.Error{
|
||||
|
@ -42,6 +42,7 @@ const deprecated = "will be removed in a future release, see https://github.com/
|
||||
var (
|
||||
packageFlags = flag.NewFlagSet("logging", flag.ContinueOnError)
|
||||
logFlushFreq time.Duration
|
||||
logrFlush func()
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -128,6 +129,9 @@ func InitLogs() {
|
||||
// are printed before exiting the program.
|
||||
func FlushLogs() {
|
||||
klog.Flush()
|
||||
if logrFlush != nil {
|
||||
logrFlush()
|
||||
}
|
||||
}
|
||||
|
||||
// NewLogger creates a new log.Logger which sends logs to klog.Info.
|
||||
|
@ -63,7 +63,9 @@ func (o *Options) Apply() {
|
||||
if factory == nil {
|
||||
klog.ClearLogger()
|
||||
} else {
|
||||
klog.SetLogger(factory.Create())
|
||||
log, flush := factory.Create(o.Config.Options)
|
||||
klog.SetLogger(log)
|
||||
logrFlush = flush
|
||||
}
|
||||
if o.Config.Sanitization {
|
||||
klog.SetLogFilter(&sanitization.SanitizingFilter{})
|
||||
|
@ -68,6 +68,7 @@ func TestOptions(t *testing.T) {
|
||||
Config: config.LoggingConfiguration{
|
||||
Format: DefaultLogFormat,
|
||||
Sanitization: true,
|
||||
Options: NewOptions().Config.Options,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -76,7 +77,8 @@ func TestOptions(t *testing.T) {
|
||||
args: []string{"--logging-format=test"},
|
||||
want: &Options{
|
||||
Config: config.LoggingConfiguration{
|
||||
Format: "test",
|
||||
Format: "test",
|
||||
Options: NewOptions().Config.Options,
|
||||
},
|
||||
},
|
||||
errs: field.ErrorList{&field.Error{
|
||||
|
@ -21,6 +21,8 @@ import (
|
||||
"sort"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
|
||||
"k8s.io/component-base/config"
|
||||
)
|
||||
|
||||
// LogRegistry is new init LogFormatRegistry struct
|
||||
@ -35,8 +37,11 @@ type LogFormatRegistry struct {
|
||||
// LogFormatFactory provides support for a certain additional,
|
||||
// non-default log format.
|
||||
type LogFormatFactory interface {
|
||||
// Create returns a logger.
|
||||
Create() logr.Logger
|
||||
// Create returns a logger with the requested configuration.
|
||||
// Returning a flush function for the logger is optional.
|
||||
// If provided, the caller must ensure that it is called
|
||||
// periodically (if desired) and at program exit.
|
||||
Create(options config.FormatOptions) (log logr.Logger, flush func())
|
||||
}
|
||||
|
||||
// NewLogFormatRegistry return new init LogFormatRegistry struct
|
||||
|
@ -37,8 +37,12 @@ func ValidateLoggingConfiguration(c *config.LoggingConfiguration, fldPath *field
|
||||
}
|
||||
}
|
||||
}
|
||||
if _, err := registry.LogRegistry.Get(c.Format); err != nil {
|
||||
_, err := registry.LogRegistry.Get(c.Format)
|
||||
if err != nil {
|
||||
errs = append(errs, field.Invalid(fldPath.Child("format"), c.Format, "Unsupported log format"))
|
||||
}
|
||||
|
||||
// Currently nothing to validate for c.Options.
|
||||
|
||||
return errs
|
||||
}
|
||||
|
@ -310,7 +310,7 @@ func (in *KubeletConfiguration) DeepCopyInto(out *KubeletConfiguration) {
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
out.Logging = in.Logging
|
||||
in.Logging.DeepCopyInto(&out.Logging)
|
||||
if in.EnableSystemLogHandler != nil {
|
||||
in, out := &in.EnableSystemLogHandler, &out.EnableSystemLogHandler
|
||||
*out = new(bool)
|
||||
|
Loading…
Reference in New Issue
Block a user