istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/networking/core/accesslog_test.go (about)

     1  // Copyright Istio Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package core
    16  
    17  import (
    18  	"testing"
    19  
    20  	accesslog "github.com/envoyproxy/go-control-plane/envoy/config/accesslog/v3"
    21  	core "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
    22  	listener "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
    23  	fileaccesslog "github.com/envoyproxy/go-control-plane/envoy/extensions/access_loggers/file/v3"
    24  	hcm "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3"
    25  	tcp "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/tcp_proxy/v3"
    26  	"github.com/envoyproxy/go-control-plane/pkg/conversion"
    27  	"github.com/google/go-cmp/cmp"
    28  	"google.golang.org/protobuf/testing/protocmp"
    29  	"google.golang.org/protobuf/types/known/wrapperspb"
    30  
    31  	meshconfig "istio.io/api/mesh/v1alpha1"
    32  	tpb "istio.io/api/telemetry/v1alpha1"
    33  	"istio.io/api/type/v1beta1"
    34  	"istio.io/istio/pilot/pkg/config/memory"
    35  	"istio.io/istio/pilot/pkg/model"
    36  	"istio.io/istio/pilot/pkg/networking"
    37  	"istio.io/istio/pilot/pkg/networking/util"
    38  	memregistry "istio.io/istio/pilot/pkg/serviceregistry/memory"
    39  	"istio.io/istio/pilot/pkg/util/protoconv"
    40  	"istio.io/istio/pilot/test/xdstest"
    41  	"istio.io/istio/pkg/config"
    42  	"istio.io/istio/pkg/config/mesh"
    43  	"istio.io/istio/pkg/config/protocol"
    44  	"istio.io/istio/pkg/config/schema/collections"
    45  	"istio.io/istio/pkg/config/schema/gvk"
    46  	"istio.io/istio/pkg/test/util/assert"
    47  	"istio.io/istio/pkg/util/protomarshal"
    48  	"istio.io/istio/pkg/wellknown"
    49  )
    50  
    51  func TestListenerAccessLog(t *testing.T) {
    52  	defaultFormatJSON, _ := protomarshal.ToJSON(model.EnvoyJSONLogFormatIstio)
    53  
    54  	for _, tc := range []struct {
    55  		name       string
    56  		encoding   meshconfig.MeshConfig_AccessLogEncoding
    57  		format     string
    58  		wantFormat string
    59  	}{
    60  		{
    61  			name:       "valid json object",
    62  			encoding:   meshconfig.MeshConfig_JSON,
    63  			format:     `{"foo": "bar"}`,
    64  			wantFormat: `{"foo":"bar"}`,
    65  		},
    66  		{
    67  			name:       "valid nested json object",
    68  			encoding:   meshconfig.MeshConfig_JSON,
    69  			format:     `{"foo": {"bar": "ha"}}`,
    70  			wantFormat: `{"foo":{"bar":"ha"}}`,
    71  		},
    72  		{
    73  			name:       "invalid json object",
    74  			encoding:   meshconfig.MeshConfig_JSON,
    75  			format:     `foo`,
    76  			wantFormat: defaultFormatJSON,
    77  		},
    78  		{
    79  			name:       "incorrect json type",
    80  			encoding:   meshconfig.MeshConfig_JSON,
    81  			format:     `[]`,
    82  			wantFormat: defaultFormatJSON,
    83  		},
    84  		{
    85  			name:       "incorrect json type",
    86  			encoding:   meshconfig.MeshConfig_JSON,
    87  			format:     `"{}"`,
    88  			wantFormat: defaultFormatJSON,
    89  		},
    90  		{
    91  			name:       "default json format",
    92  			encoding:   meshconfig.MeshConfig_JSON,
    93  			wantFormat: defaultFormatJSON,
    94  		},
    95  		{
    96  			name:       "default text format",
    97  			encoding:   meshconfig.MeshConfig_TEXT,
    98  			wantFormat: model.EnvoyTextLogFormat,
    99  		},
   100  	} {
   101  		tc := tc
   102  		t.Run(tc.name, func(t *testing.T) {
   103  			accessLogBuilder.reset()
   104  			// Update MeshConfig
   105  			m := mesh.DefaultMeshConfig()
   106  			m.AccessLogFile = "foo"
   107  			m.AccessLogEncoding = tc.encoding
   108  			m.AccessLogFormat = tc.format
   109  			listeners := buildListeners(t, TestOptions{MeshConfig: m}, nil)
   110  			if len(listeners) != 2 {
   111  				t.Errorf("expected to have 2 listeners, but got %v", len(listeners))
   112  			}
   113  			// Validate that access log filter uses the new format.
   114  			for _, l := range listeners {
   115  				if l.AccessLog[0].Filter == nil {
   116  					t.Fatal("expected filter config in listener access log configuration")
   117  				}
   118  				// Verify listener access log.
   119  				verify(t, tc.encoding, l.AccessLog[0], tc.wantFormat)
   120  
   121  				for _, fc := range l.FilterChains {
   122  					for _, filter := range fc.Filters {
   123  						switch filter.Name {
   124  						case wellknown.TCPProxy:
   125  							tcpConfig := &tcp.TcpProxy{}
   126  							if err := filter.GetTypedConfig().UnmarshalTo(tcpConfig); err != nil {
   127  								t.Fatal(err)
   128  							}
   129  							if tcpConfig.GetCluster() == util.BlackHoleCluster {
   130  								// Ignore the tcp_proxy filter with black hole cluster that just doesn't have access log.
   131  								continue
   132  							}
   133  							if len(tcpConfig.AccessLog) < 1 {
   134  								t.Fatalf("tcp_proxy want at least 1 access log, got 0")
   135  							}
   136  
   137  							for _, tcpAccessLog := range tcpConfig.AccessLog {
   138  								if tcpAccessLog.Filter != nil {
   139  									t.Fatalf("tcp_proxy filter chain's accesslog filter must be empty")
   140  								}
   141  							}
   142  
   143  							// Verify tcp proxy access log.
   144  							verify(t, tc.encoding, tcpConfig.AccessLog[0], tc.wantFormat)
   145  						case wellknown.HTTPConnectionManager:
   146  							httpConfig := &hcm.HttpConnectionManager{}
   147  							if err := filter.GetTypedConfig().UnmarshalTo(httpConfig); err != nil {
   148  								t.Fatal(err)
   149  							}
   150  							if len(httpConfig.AccessLog) < 1 {
   151  								t.Fatalf("http_connection_manager want at least 1 access log, got 0")
   152  							}
   153  							// Verify HTTP connection manager access log.
   154  							verify(t, tc.encoding, httpConfig.AccessLog[0], tc.wantFormat)
   155  						}
   156  					}
   157  				}
   158  			}
   159  		})
   160  	}
   161  }
   162  
   163  func verify(t *testing.T, encoding meshconfig.MeshConfig_AccessLogEncoding, got *accesslog.AccessLog, wantFormat string) {
   164  	cfg, _ := conversion.MessageToStruct(got.GetTypedConfig())
   165  	if encoding == meshconfig.MeshConfig_JSON {
   166  		jsonFormat := cfg.GetFields()["log_format"].GetStructValue().GetFields()["json_format"]
   167  		jsonFormatString, _ := protomarshal.ToJSON(jsonFormat)
   168  		if jsonFormatString != wantFormat {
   169  			t.Errorf("\nwant: %s\n got: %s", wantFormat, jsonFormatString)
   170  		}
   171  	} else {
   172  		textFormatString := cfg.GetFields()["log_format"].GetStructValue().GetFields()["text_format_source"].GetStructValue().
   173  			GetFields()["inline_string"].GetStringValue()
   174  		if textFormatString != wantFormat {
   175  			t.Errorf("\nwant: %s\n got: %s", wantFormat, textFormatString)
   176  		}
   177  	}
   178  }
   179  
   180  func TestAccessLogPatch(t *testing.T) {
   181  	// Regression test for https://github.com/istio/istio/issues/35778
   182  	cg := NewConfigGenTest(t, TestOptions{
   183  		Configs:        nil,
   184  		ConfigPointers: nil,
   185  		ConfigString: `
   186  apiVersion: networking.istio.io/v1alpha3
   187  kind: EnvoyFilter
   188  metadata:
   189    name: access-log-format
   190    namespace: default
   191  spec:
   192    configPatches:
   193    - applyTo: NETWORK_FILTER
   194      match:
   195        context: ANY
   196        listener:
   197          filterChain:
   198            filter:
   199              name: envoy.filters.network.tcp_proxy
   200      patch:
   201        operation: MERGE
   202        value:
   203          typed_config:
   204            '@type': type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
   205            access_log:
   206            - name: envoy.access_loggers.stream
   207              typed_config:
   208                '@type': type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
   209                log_format:
   210                  json_format:
   211                    envoyproxy_authority: '%REQ(:AUTHORITY)%'
   212  `,
   213  	})
   214  
   215  	proxy := cg.SetupProxy(nil)
   216  	l1 := cg.Listeners(proxy)
   217  	l2 := cg.Listeners(proxy)
   218  	// Make sure it doesn't change between patches
   219  	if d := cmp.Diff(l1, l2, protocmp.Transform()); d != "" {
   220  		t.Fatal(d)
   221  	}
   222  	// Make sure we have exactly 1 access log
   223  	fc := xdstest.ExtractFilterChain("virtualOutbound-blackhole", xdstest.ExtractListener("virtualOutbound", l1))
   224  	if len(xdstest.ExtractTCPProxy(t, fc).GetAccessLog()) != 1 {
   225  		t.Fatalf("unexpected access log: %v", xdstest.ExtractTCPProxy(t, fc).GetAccessLog())
   226  	}
   227  }
   228  
   229  func newTestEnviroment() *model.Environment {
   230  	serviceDiscovery := memregistry.NewServiceDiscovery(&model.Service{
   231  		Hostname:       "test.example.org",
   232  		DefaultAddress: "1.1.1.1",
   233  		Ports: model.PortList{
   234  			&model.Port{
   235  				Name:     "default",
   236  				Port:     8080,
   237  				Protocol: protocol.HTTP,
   238  			},
   239  		},
   240  	})
   241  
   242  	meshConfig := mesh.DefaultMeshConfig()
   243  	meshConfig.AccessLogFile = model.DevStdout
   244  	meshConfig.ExtensionProviders = append(meshConfig.ExtensionProviders, &meshconfig.MeshConfig_ExtensionProvider{
   245  		Name: "envoy-json",
   246  		Provider: &meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLog{
   247  			EnvoyFileAccessLog: &meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLogProvider{
   248  				Path: model.DevStdout,
   249  				LogFormat: &meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLogProvider_LogFormat{
   250  					LogFormat: &meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLogProvider_LogFormat_Labels{},
   251  				},
   252  			},
   253  		},
   254  	})
   255  
   256  	configStore := memory.Make(collections.Pilot)
   257  	configStore.Create(config.Config{
   258  		Meta: config.Meta{
   259  			Name:             "test",
   260  			Namespace:        "default",
   261  			GroupVersionKind: gvk.Telemetry,
   262  		},
   263  		Spec: &tpb.Telemetry{
   264  			Selector: &v1beta1.WorkloadSelector{
   265  				MatchLabels: map[string]string{
   266  					"app": "test",
   267  				},
   268  			},
   269  			AccessLogging: []*tpb.AccessLogging{
   270  				{
   271  					Providers: []*tpb.ProviderRef{
   272  						{
   273  							Name: "envoy-json",
   274  						},
   275  					},
   276  				},
   277  			},
   278  		},
   279  	})
   280  	configStore.Create(config.Config{
   281  		Meta: config.Meta{
   282  			Name:             "test-with-server-accesslog-filter",
   283  			Namespace:        "default",
   284  			GroupVersionKind: gvk.Telemetry,
   285  		},
   286  		Spec: &tpb.Telemetry{
   287  			Selector: &v1beta1.WorkloadSelector{
   288  				MatchLabels: map[string]string{
   289  					"app": "test-with-server-accesslog-filter",
   290  				},
   291  			},
   292  			AccessLogging: []*tpb.AccessLogging{
   293  				{
   294  					Match: &tpb.AccessLogging_LogSelector{
   295  						Mode: tpb.WorkloadMode_SERVER,
   296  					},
   297  					Providers: []*tpb.ProviderRef{
   298  						{
   299  							Name: "envoy-json",
   300  						},
   301  					},
   302  				},
   303  			},
   304  		},
   305  	})
   306  	configStore.Create(config.Config{
   307  		Meta: config.Meta{
   308  			Name:             "test-disable-accesslog",
   309  			Namespace:        "default",
   310  			GroupVersionKind: gvk.Telemetry,
   311  		},
   312  		Spec: &tpb.Telemetry{
   313  			Selector: &v1beta1.WorkloadSelector{
   314  				MatchLabels: map[string]string{
   315  					"app": "test-disable-accesslog",
   316  				},
   317  			},
   318  			AccessLogging: []*tpb.AccessLogging{
   319  				{
   320  					Providers: []*tpb.ProviderRef{
   321  						{
   322  							Name: "envoy",
   323  						},
   324  					},
   325  					Disabled: wrapperspb.Bool(true),
   326  				},
   327  			},
   328  		},
   329  	})
   330  
   331  	env := model.NewEnvironment()
   332  	env.ServiceDiscovery = serviceDiscovery
   333  	env.ConfigStore = configStore
   334  	env.Watcher = mesh.NewFixedWatcher(meshConfig)
   335  
   336  	pushContext := model.NewPushContext()
   337  	env.Init()
   338  	pushContext.InitContext(env, nil, nil)
   339  	env.SetPushContext(pushContext)
   340  
   341  	return env
   342  }
   343  
   344  var (
   345  	defaultJSONLabelsOut = &fileaccesslog.FileAccessLog{
   346  		Path: model.DevStdout,
   347  		AccessLogFormat: &fileaccesslog.FileAccessLog_LogFormat{
   348  			LogFormat: &core.SubstitutionFormatString{
   349  				Format: &core.SubstitutionFormatString_JsonFormat{
   350  					JsonFormat: model.EnvoyJSONLogFormatIstio,
   351  				},
   352  				JsonFormatOptions: &core.JsonFormatOptions{SortProperties: true},
   353  			},
   354  		},
   355  	}
   356  
   357  	defaultOut = &fileaccesslog.FileAccessLog{
   358  		Path: model.DevStdout,
   359  		AccessLogFormat: &fileaccesslog.FileAccessLog_LogFormat{
   360  			LogFormat: &core.SubstitutionFormatString{
   361  				Format: &core.SubstitutionFormatString_TextFormatSource{
   362  					TextFormatSource: &core.DataSource{
   363  						Specifier: &core.DataSource_InlineString{
   364  							InlineString: model.EnvoyTextLogFormat,
   365  						},
   366  					},
   367  				},
   368  			},
   369  		},
   370  	}
   371  )
   372  
   373  func TestSetTCPAccessLog(t *testing.T) {
   374  	b := newAccessLogBuilder()
   375  
   376  	env := newTestEnviroment()
   377  
   378  	cases := []struct {
   379  		name     string
   380  		push     *model.PushContext
   381  		proxy    *model.Proxy
   382  		tcp      *tcp.TcpProxy
   383  		class    networking.ListenerClass
   384  		expected *tcp.TcpProxy
   385  	}{
   386  		{
   387  			name: "telemetry",
   388  			push: env.PushContext(),
   389  			proxy: &model.Proxy{
   390  				ConfigNamespace: "default",
   391  				Labels:          map[string]string{"app": "test"},
   392  				Metadata:        &model.NodeMetadata{Labels: map[string]string{"app": "test"}},
   393  			},
   394  			tcp:   &tcp.TcpProxy{},
   395  			class: networking.ListenerClassSidecarInbound,
   396  			expected: &tcp.TcpProxy{
   397  				AccessLog: []*accesslog.AccessLog{
   398  					{
   399  						Name:       wellknown.FileAccessLog,
   400  						ConfigType: &accesslog.AccessLog_TypedConfig{TypedConfig: protoconv.MessageToAny(defaultJSONLabelsOut)},
   401  					},
   402  				},
   403  			},
   404  		},
   405  		{
   406  			name: "log-selector-unmatched-telemetry",
   407  			push: env.PushContext(),
   408  			proxy: &model.Proxy{
   409  				ConfigNamespace: "default",
   410  				Labels:          map[string]string{"app": "test-with-server-accesslog-filter"},
   411  				Metadata:        &model.NodeMetadata{Labels: map[string]string{"app": "test-with-server-accesslog-filter"}},
   412  			},
   413  			tcp:   &tcp.TcpProxy{},
   414  			class: networking.ListenerClassSidecarOutbound,
   415  			expected: &tcp.TcpProxy{
   416  				AccessLog: []*accesslog.AccessLog{
   417  					{
   418  						Name:       wellknown.FileAccessLog,
   419  						ConfigType: &accesslog.AccessLog_TypedConfig{TypedConfig: protoconv.MessageToAny(defaultOut)},
   420  					},
   421  				},
   422  			},
   423  		},
   424  		{
   425  			name: "without-telemetry",
   426  			push: env.PushContext(),
   427  			proxy: &model.Proxy{
   428  				ConfigNamespace: "default",
   429  				Labels:          map[string]string{"app": "without-telemetry"},
   430  				Metadata:        &model.NodeMetadata{Labels: map[string]string{"app": "without-telemetry"}},
   431  			},
   432  			tcp:   &tcp.TcpProxy{},
   433  			class: networking.ListenerClassSidecarInbound,
   434  			expected: &tcp.TcpProxy{
   435  				AccessLog: []*accesslog.AccessLog{
   436  					{
   437  						Name:       wellknown.FileAccessLog,
   438  						ConfigType: &accesslog.AccessLog_TypedConfig{TypedConfig: protoconv.MessageToAny(defaultOut)},
   439  					},
   440  				},
   441  			},
   442  		},
   443  		{
   444  			name: "disable-accesslog",
   445  			push: env.PushContext(),
   446  			proxy: &model.Proxy{
   447  				ConfigNamespace: "default",
   448  				Labels:          map[string]string{"app": "test-disable-accesslog"},
   449  				Metadata:        &model.NodeMetadata{Labels: map[string]string{"app": "test-disable-accesslog"}},
   450  			},
   451  			tcp:      &tcp.TcpProxy{},
   452  			class:    networking.ListenerClassSidecarInbound,
   453  			expected: &tcp.TcpProxy{},
   454  		},
   455  	}
   456  
   457  	for _, tc := range cases {
   458  		t.Run(tc.name, func(t *testing.T) {
   459  			b.setTCPAccessLog(tc.push, tc.proxy, tc.tcp, tc.class, nil)
   460  			assert.Equal(t, tc.expected, tc.tcp)
   461  		})
   462  	}
   463  }
   464  
   465  func TestSetHttpAccessLog(t *testing.T) {
   466  	b := newAccessLogBuilder()
   467  
   468  	env := newTestEnviroment()
   469  
   470  	cases := []struct {
   471  		name     string
   472  		push     *model.PushContext
   473  		proxy    *model.Proxy
   474  		hcm      *hcm.HttpConnectionManager
   475  		class    networking.ListenerClass
   476  		expected *hcm.HttpConnectionManager
   477  	}{
   478  		{
   479  			name: "telemetry",
   480  			push: env.PushContext(),
   481  			proxy: &model.Proxy{
   482  				ConfigNamespace: "default",
   483  				Labels:          map[string]string{"app": "test"},
   484  				Metadata:        &model.NodeMetadata{Labels: map[string]string{"app": "test"}},
   485  			},
   486  			hcm:   &hcm.HttpConnectionManager{},
   487  			class: networking.ListenerClassSidecarInbound,
   488  			expected: &hcm.HttpConnectionManager{
   489  				AccessLog: []*accesslog.AccessLog{
   490  					{
   491  						Name:       wellknown.FileAccessLog,
   492  						ConfigType: &accesslog.AccessLog_TypedConfig{TypedConfig: protoconv.MessageToAny(defaultJSONLabelsOut)},
   493  					},
   494  				},
   495  			},
   496  		},
   497  		{
   498  			name: "log-selector-unmatched-telemetry",
   499  			push: env.PushContext(),
   500  			proxy: &model.Proxy{
   501  				ConfigNamespace: "default",
   502  				Labels:          map[string]string{"app": "test-with-server-accesslog-filter"},
   503  				Metadata:        &model.NodeMetadata{Labels: map[string]string{"app": "test-with-server-accesslog-filter"}},
   504  			},
   505  			hcm:   &hcm.HttpConnectionManager{},
   506  			class: networking.ListenerClassSidecarOutbound,
   507  			expected: &hcm.HttpConnectionManager{
   508  				AccessLog: []*accesslog.AccessLog{
   509  					{
   510  						Name:       wellknown.FileAccessLog,
   511  						ConfigType: &accesslog.AccessLog_TypedConfig{TypedConfig: protoconv.MessageToAny(defaultOut)},
   512  					},
   513  				},
   514  			},
   515  		},
   516  		{
   517  			name: "without-telemetry",
   518  			push: env.PushContext(),
   519  			proxy: &model.Proxy{
   520  				ConfigNamespace: "default",
   521  				Labels:          map[string]string{"app": "without-telemetry"},
   522  				Metadata:        &model.NodeMetadata{Labels: map[string]string{"app": "without-telemetry"}},
   523  			},
   524  			hcm:   &hcm.HttpConnectionManager{},
   525  			class: networking.ListenerClassSidecarInbound,
   526  			expected: &hcm.HttpConnectionManager{
   527  				AccessLog: []*accesslog.AccessLog{
   528  					{
   529  						Name:       wellknown.FileAccessLog,
   530  						ConfigType: &accesslog.AccessLog_TypedConfig{TypedConfig: protoconv.MessageToAny(defaultOut)},
   531  					},
   532  				},
   533  			},
   534  		},
   535  		{
   536  			name: "disable-accesslog",
   537  			push: env.PushContext(),
   538  			proxy: &model.Proxy{
   539  				ConfigNamespace: "default",
   540  				Labels:          map[string]string{"app": "test-disable-accesslog"},
   541  				Metadata:        &model.NodeMetadata{Labels: map[string]string{"app": "test-disable-accesslog"}},
   542  			},
   543  			hcm:      &hcm.HttpConnectionManager{},
   544  			class:    networking.ListenerClassSidecarInbound,
   545  			expected: &hcm.HttpConnectionManager{},
   546  		},
   547  	}
   548  
   549  	for _, tc := range cases {
   550  		t.Run(tc.name, func(t *testing.T) {
   551  			b.setHTTPAccessLog(tc.push, tc.proxy, tc.hcm, tc.class, nil)
   552  			assert.Equal(t, tc.expected, tc.hcm)
   553  		})
   554  	}
   555  }
   556  
   557  func TestSetListenerAccessLog(t *testing.T) {
   558  	b := newAccessLogBuilder()
   559  
   560  	env := newTestEnviroment()
   561  
   562  	cases := []struct {
   563  		name     string
   564  		push     *model.PushContext
   565  		proxy    *model.Proxy
   566  		listener *listener.Listener
   567  		class    networking.ListenerClass
   568  		expected *listener.Listener
   569  	}{
   570  		{
   571  			name: "telemetry",
   572  			push: env.PushContext(),
   573  			proxy: &model.Proxy{
   574  				ConfigNamespace: "default",
   575  				Labels:          map[string]string{"app": "test"},
   576  				Metadata:        &model.NodeMetadata{Labels: map[string]string{"app": "test"}},
   577  			},
   578  			listener: &listener.Listener{},
   579  			class:    networking.ListenerClassSidecarInbound,
   580  			expected: &listener.Listener{
   581  				AccessLog: []*accesslog.AccessLog{
   582  					{
   583  						Name: wellknown.FileAccessLog,
   584  						Filter: &accesslog.AccessLogFilter{
   585  							FilterSpecifier: &accesslog.AccessLogFilter_ResponseFlagFilter{
   586  								ResponseFlagFilter: &accesslog.ResponseFlagFilter{Flags: []string{"NR"}},
   587  							},
   588  						},
   589  						ConfigType: &accesslog.AccessLog_TypedConfig{TypedConfig: protoconv.MessageToAny(defaultJSONLabelsOut)},
   590  					},
   591  				},
   592  			},
   593  		},
   594  		{
   595  			name: "log-selector-unmatched-telemetry",
   596  			push: env.PushContext(),
   597  			proxy: &model.Proxy{
   598  				ConfigNamespace: "default",
   599  				Labels:          map[string]string{"app": "test-with-server-accesslog-filter"},
   600  				Metadata:        &model.NodeMetadata{Labels: map[string]string{"app": "test-with-server-accesslog-filter"}},
   601  			},
   602  			listener: &listener.Listener{},
   603  			class:    networking.ListenerClassSidecarOutbound,
   604  			expected: &listener.Listener{
   605  				AccessLog: []*accesslog.AccessLog{
   606  					{
   607  						Name: wellknown.FileAccessLog,
   608  						Filter: &accesslog.AccessLogFilter{
   609  							FilterSpecifier: &accesslog.AccessLogFilter_ResponseFlagFilter{
   610  								ResponseFlagFilter: &accesslog.ResponseFlagFilter{Flags: []string{"NR"}},
   611  							},
   612  						},
   613  						ConfigType: &accesslog.AccessLog_TypedConfig{TypedConfig: protoconv.MessageToAny(defaultOut)},
   614  					},
   615  				},
   616  			},
   617  		},
   618  		{
   619  			name: "without-telemetry",
   620  			push: env.PushContext(),
   621  			proxy: &model.Proxy{
   622  				ConfigNamespace: "default",
   623  				Labels:          map[string]string{"app": "without-telemetry"},
   624  				Metadata:        &model.NodeMetadata{Labels: map[string]string{"app": "without-telemetry"}},
   625  			},
   626  			listener: &listener.Listener{},
   627  			class:    networking.ListenerClassSidecarInbound,
   628  			expected: &listener.Listener{
   629  				AccessLog: []*accesslog.AccessLog{
   630  					{
   631  						Name: wellknown.FileAccessLog,
   632  						Filter: &accesslog.AccessLogFilter{
   633  							FilterSpecifier: &accesslog.AccessLogFilter_ResponseFlagFilter{
   634  								ResponseFlagFilter: &accesslog.ResponseFlagFilter{Flags: []string{"NR"}},
   635  							},
   636  						},
   637  						ConfigType: &accesslog.AccessLog_TypedConfig{TypedConfig: protoconv.MessageToAny(defaultOut)},
   638  					},
   639  				},
   640  			},
   641  		},
   642  		{
   643  			name: "disable-accesslog",
   644  			push: env.PushContext(),
   645  			proxy: &model.Proxy{
   646  				ConfigNamespace: "default",
   647  				Labels:          map[string]string{"app": "test-disable-accesslog"},
   648  				Metadata:        &model.NodeMetadata{Labels: map[string]string{"app": "test-disable-accesslog"}},
   649  			},
   650  			listener: &listener.Listener{},
   651  			class:    networking.ListenerClassSidecarInbound,
   652  			expected: &listener.Listener{},
   653  		},
   654  	}
   655  
   656  	for _, tc := range cases {
   657  		t.Run(tc.name, func(t *testing.T) {
   658  			b.setListenerAccessLog(tc.push, tc.proxy, tc.listener, tc.class)
   659  			assert.Equal(t, tc.expected, tc.listener)
   660  		})
   661  	}
   662  }