istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/model/telemetry_logging_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 model
    16  
    17  import (
    18  	"reflect"
    19  	"sort"
    20  	"testing"
    21  
    22  	accesslog "github.com/envoyproxy/go-control-plane/envoy/config/accesslog/v3"
    23  	core "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
    24  	fileaccesslog "github.com/envoyproxy/go-control-plane/envoy/extensions/access_loggers/file/v3"
    25  	grpcaccesslog "github.com/envoyproxy/go-control-plane/envoy/extensions/access_loggers/grpc/v3"
    26  	otelaccesslog "github.com/envoyproxy/go-control-plane/envoy/extensions/access_loggers/open_telemetry/v3"
    27  	otlpcommon "go.opentelemetry.io/proto/otlp/common/v1"
    28  	"google.golang.org/protobuf/types/known/structpb"
    29  	wrappers "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/networking"
    35  	"istio.io/istio/pilot/pkg/serviceregistry/provider"
    36  	"istio.io/istio/pilot/pkg/util/protoconv"
    37  	"istio.io/istio/pkg/config"
    38  	"istio.io/istio/pkg/config/protocol"
    39  	"istio.io/istio/pkg/config/schema/gvk"
    40  	"istio.io/istio/pkg/test/util/assert"
    41  	"istio.io/istio/pkg/util/protomarshal"
    42  	"istio.io/istio/pkg/wellknown"
    43  )
    44  
    45  func TestFileAccessLogFormat(t *testing.T) {
    46  	cases := []struct {
    47  		name         string
    48  		formatString string
    49  		expected     string
    50  	}{
    51  		{
    52  			name:     "empty",
    53  			expected: EnvoyTextLogFormat,
    54  		},
    55  		{
    56  			name:         "contains newline",
    57  			formatString: "[%START_TIME%] %REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% \n",
    58  			expected:     "[%START_TIME%] %REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% \n",
    59  		},
    60  		{
    61  			name:         "miss newline",
    62  			formatString: "[%START_TIME%] %REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%",
    63  			expected:     "[%START_TIME%] %REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%\n",
    64  		},
    65  	}
    66  
    67  	for _, tc := range cases {
    68  		t.Run(tc.name, func(t *testing.T) {
    69  			got := fileAccessLogFormat(tc.formatString)
    70  			assert.Equal(t, tc.expected, got)
    71  		})
    72  	}
    73  }
    74  
    75  func TestAccessLogging(t *testing.T) {
    76  	labels := map[string]string{"app": "test"}
    77  	sidecar := &Proxy{
    78  		ConfigNamespace: "default",
    79  		Labels:          labels,
    80  		Metadata:        &NodeMetadata{Labels: labels},
    81  	}
    82  	prometheus := &tpb.Telemetry{
    83  		Metrics: []*tpb.Metrics{
    84  			{
    85  				Providers: []*tpb.ProviderRef{
    86  					{
    87  						Name: "envoy",
    88  					},
    89  				},
    90  			},
    91  		},
    92  	}
    93  	envoy := &tpb.Telemetry{
    94  		AccessLogging: []*tpb.AccessLogging{
    95  			{
    96  				Providers: []*tpb.ProviderRef{
    97  					{
    98  						Name: "envoy",
    99  					},
   100  				},
   101  			},
   102  		},
   103  	}
   104  	client := &tpb.Telemetry{
   105  		AccessLogging: []*tpb.AccessLogging{
   106  			{
   107  				Match: &tpb.AccessLogging_LogSelector{
   108  					Mode: tpb.WorkloadMode_CLIENT,
   109  				},
   110  				Providers: []*tpb.ProviderRef{
   111  					{
   112  						Name: "envoy",
   113  					},
   114  				},
   115  			},
   116  		},
   117  	}
   118  	clientDisabled := &tpb.Telemetry{
   119  		AccessLogging: []*tpb.AccessLogging{
   120  			{
   121  				Match: &tpb.AccessLogging_LogSelector{
   122  					Mode: tpb.WorkloadMode_CLIENT,
   123  				},
   124  				Providers: []*tpb.ProviderRef{
   125  					{
   126  						Name: "envoy",
   127  					},
   128  				},
   129  				Disabled: &wrappers.BoolValue{
   130  					Value: true,
   131  				},
   132  			},
   133  		},
   134  	}
   135  	targetRefClient := &tpb.Telemetry{
   136  		TargetRef: &v1beta1.PolicyTargetReference{
   137  			Group: gvk.KubernetesGateway.Group,
   138  			Kind:  gvk.KubernetesGateway.Kind,
   139  			Name:  "my-gateway",
   140  		},
   141  		AccessLogging: []*tpb.AccessLogging{
   142  			{
   143  				Match: &tpb.AccessLogging_LogSelector{
   144  					Mode: tpb.WorkloadMode_CLIENT,
   145  				},
   146  				Providers: []*tpb.ProviderRef{
   147  					{
   148  						Name: "envoy",
   149  					},
   150  				},
   151  			},
   152  		},
   153  	}
   154  	sidecarClient := &tpb.Telemetry{
   155  		Selector: &v1beta1.WorkloadSelector{
   156  			MatchLabels: labels,
   157  		},
   158  		AccessLogging: []*tpb.AccessLogging{
   159  			{
   160  				Match: &tpb.AccessLogging_LogSelector{
   161  					Mode: tpb.WorkloadMode_CLIENT,
   162  				},
   163  				Providers: []*tpb.ProviderRef{
   164  					{
   165  						Name: "envoy",
   166  					},
   167  				},
   168  			},
   169  		},
   170  	}
   171  	server := &tpb.Telemetry{
   172  		AccessLogging: []*tpb.AccessLogging{
   173  			{
   174  				Match: &tpb.AccessLogging_LogSelector{
   175  					Mode: tpb.WorkloadMode_SERVER,
   176  				},
   177  				Providers: []*tpb.ProviderRef{
   178  					{
   179  						Name: "envoy",
   180  					},
   181  				},
   182  			},
   183  		},
   184  	}
   185  	serverDisabled := &tpb.Telemetry{
   186  		AccessLogging: []*tpb.AccessLogging{
   187  			{
   188  				Match: &tpb.AccessLogging_LogSelector{
   189  					Mode: tpb.WorkloadMode_SERVER,
   190  				},
   191  				Providers: []*tpb.ProviderRef{
   192  					{
   193  						Name: "envoy",
   194  					},
   195  				},
   196  				Disabled: &wrappers.BoolValue{
   197  					Value: true,
   198  				},
   199  			},
   200  		},
   201  	}
   202  	serverAndClient := &tpb.Telemetry{
   203  		AccessLogging: []*tpb.AccessLogging{
   204  			{
   205  				Match: &tpb.AccessLogging_LogSelector{
   206  					Mode: tpb.WorkloadMode_CLIENT_AND_SERVER,
   207  				},
   208  				Providers: []*tpb.ProviderRef{
   209  					{
   210  						Name: "envoy",
   211  					},
   212  				},
   213  			},
   214  		},
   215  	}
   216  	stackdriver := &tpb.Telemetry{
   217  		AccessLogging: []*tpb.AccessLogging{
   218  			{
   219  				Providers: []*tpb.ProviderRef{
   220  					{
   221  						Name: "stackdriver",
   222  					},
   223  				},
   224  			},
   225  		},
   226  	}
   227  	empty := &tpb.Telemetry{
   228  		AccessLogging: []*tpb.AccessLogging{{}},
   229  	}
   230  	defaultJSON := &tpb.Telemetry{
   231  		AccessLogging: []*tpb.AccessLogging{
   232  			{
   233  				Providers: []*tpb.ProviderRef{
   234  					{
   235  						Name: "envoy-json",
   236  					},
   237  				},
   238  			},
   239  		},
   240  	}
   241  	disabled := &tpb.Telemetry{
   242  		AccessLogging: []*tpb.AccessLogging{
   243  			{
   244  				Disabled: &wrappers.BoolValue{Value: true},
   245  			},
   246  		},
   247  	}
   248  	nonExistant := &tpb.Telemetry{
   249  		AccessLogging: []*tpb.AccessLogging{
   250  			{
   251  				Providers: []*tpb.ProviderRef{
   252  					{
   253  						Name: "custom-provider",
   254  					},
   255  				},
   256  			},
   257  		},
   258  	}
   259  	multiAccessLogging := &tpb.Telemetry{
   260  		AccessLogging: []*tpb.AccessLogging{
   261  			{
   262  				Providers: []*tpb.ProviderRef{
   263  					{
   264  						Name: "envoy",
   265  					},
   266  				},
   267  			},
   268  			{
   269  				Providers: []*tpb.ProviderRef{
   270  					{
   271  						Name: "envoy-json",
   272  					},
   273  				},
   274  			},
   275  		},
   276  	}
   277  	multiAccessLoggingWithDisabled := &tpb.Telemetry{
   278  		AccessLogging: []*tpb.AccessLogging{
   279  			{
   280  				Providers: []*tpb.ProviderRef{
   281  					{
   282  						Name: "envoy",
   283  					},
   284  				},
   285  			},
   286  			{
   287  				Providers: []*tpb.ProviderRef{
   288  					{
   289  						Name: "envoy-json",
   290  					},
   291  				},
   292  				Disabled: &wrappers.BoolValue{
   293  					Value: true,
   294  				},
   295  			},
   296  		},
   297  	}
   298  	multiAccessLoggingAndProviders := &tpb.Telemetry{
   299  		AccessLogging: []*tpb.AccessLogging{
   300  			{
   301  				Providers: []*tpb.ProviderRef{
   302  					{
   303  						Name: "envoy",
   304  					},
   305  					{
   306  						Name: "envoy-json",
   307  					},
   308  				},
   309  			},
   310  			{
   311  				Providers: []*tpb.ProviderRef{
   312  					{
   313  						Name: "envoy",
   314  					},
   315  				},
   316  			},
   317  		},
   318  	}
   319  	multiFilters := &tpb.Telemetry{
   320  		AccessLogging: []*tpb.AccessLogging{
   321  			{
   322  				Match: &tpb.AccessLogging_LogSelector{
   323  					Mode: tpb.WorkloadMode_SERVER,
   324  				},
   325  				Providers: []*tpb.ProviderRef{
   326  					{
   327  						Name: "envoy",
   328  					},
   329  				},
   330  			},
   331  			{
   332  				Match: &tpb.AccessLogging_LogSelector{
   333  					Mode: tpb.WorkloadMode_CLIENT_AND_SERVER, // pickup last filter
   334  				},
   335  				Providers: []*tpb.ProviderRef{
   336  					{
   337  						Name: "envoy",
   338  					},
   339  				},
   340  			},
   341  		},
   342  	}
   343  	multiFiltersDisabled := &tpb.Telemetry{
   344  		AccessLogging: []*tpb.AccessLogging{
   345  			{
   346  				Match: &tpb.AccessLogging_LogSelector{
   347  					Mode: tpb.WorkloadMode_SERVER,
   348  				},
   349  				Providers: []*tpb.ProviderRef{
   350  					{
   351  						Name: "envoy",
   352  					},
   353  				},
   354  			},
   355  			{
   356  				Match: &tpb.AccessLogging_LogSelector{
   357  					Mode: tpb.WorkloadMode_CLIENT_AND_SERVER, // pickup last filter
   358  				},
   359  				Providers: []*tpb.ProviderRef{
   360  					{
   361  						Name: "envoy",
   362  					},
   363  				},
   364  				Disabled: &wrappers.BoolValue{
   365  					Value: true,
   366  				},
   367  			},
   368  		},
   369  	}
   370  	serverAndClientDifferent := &tpb.Telemetry{
   371  		AccessLogging: []*tpb.AccessLogging{
   372  			{
   373  				Match: &tpb.AccessLogging_LogSelector{
   374  					Mode: tpb.WorkloadMode_SERVER,
   375  				},
   376  				Providers: []*tpb.ProviderRef{
   377  					{
   378  						Name: "envoy",
   379  					},
   380  				},
   381  			},
   382  			{
   383  				Match: &tpb.AccessLogging_LogSelector{
   384  					Mode: tpb.WorkloadMode_CLIENT,
   385  				},
   386  				Providers: []*tpb.ProviderRef{
   387  					{
   388  						Name: "envoy-json",
   389  					},
   390  				},
   391  			},
   392  		},
   393  	}
   394  	tests := []struct {
   395  		name             string
   396  		cfgs             []config.Config
   397  		class            networking.ListenerClass
   398  		proxy            *Proxy
   399  		defaultProviders []string
   400  		want             []string
   401  	}{
   402  		{
   403  			"empty",
   404  			nil,
   405  			networking.ListenerClassSidecarOutbound,
   406  			sidecar,
   407  			nil,
   408  			nil, // No Telemetry API configured, fall back to legacy mesh config setting
   409  		},
   410  		{
   411  			"prometheus-mesh",
   412  			[]config.Config{newTelemetry("istio-system", prometheus)},
   413  			networking.ListenerClassSidecarOutbound,
   414  			sidecar,
   415  			nil,
   416  			nil, // No Telemetry API configured, fall back to legacy mesh config setting
   417  		},
   418  		{
   419  			"prometheus-namespace",
   420  			[]config.Config{newTelemetry("default", prometheus)},
   421  			networking.ListenerClassSidecarOutbound,
   422  			sidecar,
   423  			nil,
   424  			nil, // No Telemetry API configured, fall back to legacy mesh config setting
   425  		},
   426  		{
   427  			"prometheus-workload",
   428  			[]config.Config{newTelemetry("default", &tpb.Telemetry{
   429  				Selector: &v1beta1.WorkloadSelector{
   430  					MatchLabels: labels,
   431  				},
   432  				Metrics: []*tpb.Metrics{
   433  					{
   434  						Providers: []*tpb.ProviderRef{
   435  							{
   436  								Name: "envoy",
   437  							},
   438  						},
   439  					},
   440  				},
   441  			})},
   442  			networking.ListenerClassSidecarOutbound,
   443  			sidecar,
   444  			nil,
   445  			nil, // No Telemetry API configured, fall back to legacy mesh config setting
   446  		},
   447  		{
   448  			"default provider only",
   449  			nil,
   450  			networking.ListenerClassSidecarOutbound,
   451  			sidecar,
   452  			[]string{"envoy"},
   453  			[]string{"envoy"},
   454  		},
   455  		{
   456  			"provider only",
   457  			[]config.Config{newTelemetry("istio-system", envoy)},
   458  			networking.ListenerClassSidecarOutbound,
   459  			sidecar,
   460  			nil,
   461  			[]string{"envoy"},
   462  		},
   463  		{
   464  			"client - gateway",
   465  			[]config.Config{newTelemetry("istio-system", client)},
   466  			networking.ListenerClassGateway,
   467  			sidecar,
   468  			nil,
   469  			[]string{"envoy"},
   470  		},
   471  		{
   472  			"client - gateway defined by targetRef",
   473  			[]config.Config{newTelemetry("default", targetRefClient)},
   474  			networking.ListenerClassGateway,
   475  			sidecar,
   476  			nil,
   477  			[]string{"envoy"},
   478  		},
   479  		{
   480  			"client - outbound",
   481  			[]config.Config{newTelemetry("istio-system", client)},
   482  			networking.ListenerClassSidecarOutbound,
   483  			sidecar,
   484  			nil,
   485  			[]string{"envoy"},
   486  		},
   487  		{
   488  			"client - inbound",
   489  			[]config.Config{newTelemetry("istio-system", client)},
   490  			networking.ListenerClassSidecarInbound,
   491  			sidecar,
   492  			nil,
   493  			[]string{},
   494  		},
   495  		{
   496  			"client - disabled server",
   497  			[]config.Config{newTelemetry("istio-system", client), newTelemetry("default", serverDisabled)},
   498  			networking.ListenerClassSidecarOutbound,
   499  			sidecar,
   500  			nil,
   501  			[]string{"envoy"},
   502  		},
   503  		{
   504  			"client - disabled client",
   505  			[]config.Config{newTelemetry("istio-system", client), newTelemetry("default", clientDisabled)},
   506  			networking.ListenerClassSidecarOutbound,
   507  			sidecar,
   508  			nil,
   509  			[]string{},
   510  		},
   511  		{
   512  			"client - disabled - enabled",
   513  			[]config.Config{newTelemetry("istio-system", client), newTelemetry("default", clientDisabled), newTelemetry("default", sidecarClient)},
   514  			networking.ListenerClassSidecarOutbound,
   515  			sidecar,
   516  			nil,
   517  			[]string{"envoy"},
   518  		},
   519  		{
   520  			"server - gateway",
   521  			[]config.Config{newTelemetry("istio-system", server)},
   522  			networking.ListenerClassGateway,
   523  			sidecar,
   524  			nil,
   525  			[]string{},
   526  		},
   527  		{
   528  			"server - inbound",
   529  			[]config.Config{newTelemetry("istio-system", server)},
   530  			networking.ListenerClassSidecarInbound,
   531  			sidecar,
   532  			nil,
   533  			[]string{"envoy"},
   534  		},
   535  		{
   536  			"server - outbound",
   537  			[]config.Config{newTelemetry("istio-system", server)},
   538  			networking.ListenerClassSidecarOutbound,
   539  			sidecar,
   540  			nil,
   541  			[]string{},
   542  		},
   543  		{
   544  			"server and client - gateway",
   545  			[]config.Config{newTelemetry("istio-system", serverAndClient)},
   546  			networking.ListenerClassGateway,
   547  			sidecar,
   548  			nil,
   549  			[]string{"envoy"},
   550  		},
   551  		{
   552  			"server and client - inbound",
   553  			[]config.Config{newTelemetry("istio-system", serverAndClient)},
   554  			networking.ListenerClassSidecarInbound,
   555  			sidecar,
   556  			nil,
   557  			[]string{"envoy"},
   558  		},
   559  		{
   560  			"server and client - outbound",
   561  			[]config.Config{newTelemetry("istio-system", serverAndClient)},
   562  			networking.ListenerClassSidecarOutbound,
   563  			sidecar,
   564  			nil,
   565  			[]string{"envoy"},
   566  		},
   567  		{
   568  			"override default",
   569  			[]config.Config{newTelemetry("istio-system", envoy)},
   570  			networking.ListenerClassSidecarOutbound,
   571  			sidecar,
   572  			[]string{"stackdriver"},
   573  			[]string{"envoy"},
   574  		},
   575  		{
   576  			"override namespace",
   577  			[]config.Config{newTelemetry("istio-system", envoy), newTelemetry("default", defaultJSON)},
   578  			networking.ListenerClassSidecarOutbound,
   579  			sidecar,
   580  			nil,
   581  			[]string{"envoy-json"},
   582  		},
   583  		{
   584  			"empty config inherits",
   585  			[]config.Config{newTelemetry("istio-system", envoy), newTelemetry("default", empty)},
   586  			networking.ListenerClassSidecarOutbound,
   587  			sidecar,
   588  			nil,
   589  			[]string{"envoy"},
   590  		},
   591  		{
   592  			"stackdriver",
   593  			[]config.Config{newTelemetry("istio-system", envoy), newTelemetry("default", stackdriver)},
   594  			networking.ListenerClassSidecarOutbound,
   595  			sidecar,
   596  			nil,
   597  			[]string{},
   598  		},
   599  		{
   600  			"default envoy JSON",
   601  			[]config.Config{newTelemetry("istio-system", defaultJSON)},
   602  			networking.ListenerClassSidecarOutbound,
   603  			sidecar,
   604  			nil,
   605  			[]string{"envoy-json"},
   606  		},
   607  		{
   608  			"disable config",
   609  			[]config.Config{newTelemetry("istio-system", envoy), newTelemetry("default", disabled)},
   610  			networking.ListenerClassSidecarOutbound,
   611  			sidecar,
   612  			nil,
   613  			[]string{},
   614  		},
   615  		{
   616  			"disable default",
   617  			[]config.Config{newTelemetry("default", disabled)},
   618  			networking.ListenerClassSidecarOutbound,
   619  			sidecar,
   620  			[]string{"envoy"},
   621  			[]string{},
   622  		},
   623  		{
   624  			"non existing",
   625  			[]config.Config{newTelemetry("default", nonExistant)},
   626  			networking.ListenerClassSidecarOutbound,
   627  			sidecar,
   628  			[]string{"envoy"},
   629  			[]string{},
   630  		},
   631  		{
   632  			"server - multi filters",
   633  			[]config.Config{newTelemetry("istio-system", multiFilters)},
   634  			networking.ListenerClassSidecarOutbound,
   635  			sidecar,
   636  			nil,
   637  			[]string{"envoy"},
   638  		},
   639  		{
   640  			"server - multi filters disabled",
   641  			[]config.Config{newTelemetry("istio-system", multiFiltersDisabled)},
   642  			networking.ListenerClassSidecarOutbound,
   643  			sidecar,
   644  			nil,
   645  			[]string{},
   646  		},
   647  		{
   648  			"multi accesslogging",
   649  			[]config.Config{newTelemetry("istio-system", envoy), newTelemetry("default", multiAccessLogging)},
   650  			networking.ListenerClassSidecarOutbound,
   651  			sidecar,
   652  			nil,
   653  			[]string{"envoy", "envoy-json"},
   654  		},
   655  		{
   656  			"multi accesslogging with disabled",
   657  			[]config.Config{newTelemetry("istio-system", envoy), newTelemetry("default", multiAccessLoggingWithDisabled)},
   658  			networking.ListenerClassSidecarOutbound,
   659  			sidecar,
   660  			nil,
   661  			[]string{"envoy"},
   662  		},
   663  		{
   664  			"multi accesslogging - multi providers",
   665  			[]config.Config{newTelemetry("istio-system", envoy), newTelemetry("default", multiAccessLoggingAndProviders)},
   666  			networking.ListenerClassSidecarOutbound,
   667  			sidecar,
   668  			nil,
   669  			[]string{"envoy", "envoy-json"},
   670  		},
   671  		{
   672  			"server and client different - inbound",
   673  			[]config.Config{newTelemetry("istio-system", serverAndClientDifferent)},
   674  			networking.ListenerClassSidecarInbound,
   675  			sidecar,
   676  			nil,
   677  			[]string{"envoy"},
   678  		},
   679  		{
   680  			"server and client different - outbound",
   681  			[]config.Config{newTelemetry("istio-system", serverAndClientDifferent)},
   682  			networking.ListenerClassSidecarOutbound,
   683  			sidecar,
   684  			nil,
   685  			[]string{"envoy-json"},
   686  		},
   687  	}
   688  	for _, tt := range tests {
   689  		t.Run(tt.name, func(t *testing.T) {
   690  			telemetry, ctx := createTestTelemetries(tt.cfgs, t)
   691  			telemetry.meshConfig.DefaultProviders.AccessLogging = tt.defaultProviders
   692  			var got []string
   693  			cfgs := telemetry.AccessLogging(ctx, tt.proxy, tt.class, nil)
   694  			if cfgs != nil {
   695  				got = []string{}
   696  				for _, p := range cfgs {
   697  					if p.Disabled {
   698  						continue
   699  					}
   700  					got = append(got, p.Provider.Name)
   701  				}
   702  				sort.Strings(got)
   703  			}
   704  			if !reflect.DeepEqual(got, tt.want) {
   705  				t.Fatalf("got %v want %v", got, tt.want)
   706  			}
   707  		})
   708  	}
   709  }
   710  
   711  func TestAccessLoggingWithFilter(t *testing.T) {
   712  	sidecar := &Proxy{
   713  		ConfigNamespace: "default",
   714  		Labels:          map[string]string{"app": "test"},
   715  		Metadata:        &NodeMetadata{},
   716  	}
   717  	code400filter := &tpb.Telemetry{
   718  		AccessLogging: []*tpb.AccessLogging{
   719  			{
   720  				Providers: []*tpb.ProviderRef{
   721  					{
   722  						Name: "envoy-json",
   723  					},
   724  				},
   725  				Filter: &tpb.AccessLogging_Filter{
   726  					Expression: "response.code >= 400",
   727  				},
   728  			},
   729  		},
   730  	}
   731  	code500filter := &tpb.Telemetry{
   732  		AccessLogging: []*tpb.AccessLogging{
   733  			{
   734  				Providers: []*tpb.ProviderRef{
   735  					{
   736  						Name: "envoy-json",
   737  					},
   738  				},
   739  				Filter: &tpb.AccessLogging_Filter{
   740  					Expression: "response.code >= 500",
   741  				},
   742  			},
   743  		},
   744  	}
   745  	multiAccessLoggingFilter := &tpb.Telemetry{
   746  		AccessLogging: []*tpb.AccessLogging{
   747  			{
   748  				Providers: []*tpb.ProviderRef{
   749  					{
   750  						Name: "envoy-json",
   751  					},
   752  				},
   753  				Filter: &tpb.AccessLogging_Filter{
   754  					Expression: "response.code >= 500",
   755  				},
   756  			},
   757  			{
   758  				Providers: []*tpb.ProviderRef{
   759  					{
   760  						Name: "envoy-json",
   761  					},
   762  				},
   763  				Filter: &tpb.AccessLogging_Filter{
   764  					Expression: "response.code >= 400",
   765  				},
   766  			},
   767  		},
   768  	}
   769  	multiAccessLoggingNilFilter := &tpb.Telemetry{
   770  		AccessLogging: []*tpb.AccessLogging{
   771  			{
   772  				Providers: []*tpb.ProviderRef{
   773  					{
   774  						Name: "envoy-json",
   775  					},
   776  				},
   777  				Filter: &tpb.AccessLogging_Filter{
   778  					Expression: "response.code >= 500",
   779  				},
   780  			},
   781  			{
   782  				Providers: []*tpb.ProviderRef{
   783  					{
   784  						Name: "envoy-json",
   785  					},
   786  				},
   787  			},
   788  		},
   789  	}
   790  	serverAndClientDifferent := &tpb.Telemetry{
   791  		AccessLogging: []*tpb.AccessLogging{
   792  			{
   793  				Match: &tpb.AccessLogging_LogSelector{
   794  					Mode: tpb.WorkloadMode_CLIENT,
   795  				},
   796  				Providers: []*tpb.ProviderRef{
   797  					{
   798  						Name: "envoy-json",
   799  					},
   800  				},
   801  				Filter: &tpb.AccessLogging_Filter{
   802  					Expression: "response.code >= 500",
   803  				},
   804  			},
   805  			{
   806  				Match: &tpb.AccessLogging_LogSelector{
   807  					Mode: tpb.WorkloadMode_SERVER,
   808  				},
   809  				Providers: []*tpb.ProviderRef{
   810  					{
   811  						Name: "envoy-json",
   812  					},
   813  				},
   814  				Filter: &tpb.AccessLogging_Filter{
   815  					Expression: "response.code >= 400",
   816  				},
   817  			},
   818  		},
   819  	}
   820  
   821  	tests := []struct {
   822  		name             string
   823  		cfgs             []config.Config
   824  		proxy            *Proxy
   825  		defaultProviders []string
   826  		excepted         []LoggingConfig
   827  	}{
   828  		{
   829  			"filter",
   830  			[]config.Config{newTelemetry("default", code400filter)},
   831  			sidecar,
   832  			[]string{"envoy"},
   833  			[]LoggingConfig{
   834  				{
   835  					AccessLog: &accesslog.AccessLog{
   836  						Name:       wellknown.FileAccessLog,
   837  						ConfigType: &accesslog.AccessLog_TypedConfig{TypedConfig: protoconv.MessageToAny(defaultJSONLabelsOut)},
   838  					},
   839  					Provider: jsonTextProvider,
   840  					Filter: &tpb.AccessLogging_Filter{
   841  						Expression: "response.code >= 400",
   842  					},
   843  				},
   844  			},
   845  		},
   846  		{
   847  			"namespace-filter",
   848  			[]config.Config{newTelemetry("istio-system", code400filter), newTelemetry("default", code500filter)},
   849  			sidecar,
   850  			[]string{"envoy"},
   851  			[]LoggingConfig{
   852  				{
   853  					AccessLog: &accesslog.AccessLog{
   854  						Name:       wellknown.FileAccessLog,
   855  						ConfigType: &accesslog.AccessLog_TypedConfig{TypedConfig: protoconv.MessageToAny(defaultJSONLabelsOut)},
   856  					},
   857  					Provider: jsonTextProvider,
   858  					Filter: &tpb.AccessLogging_Filter{
   859  						Expression: "response.code >= 500",
   860  					},
   861  				},
   862  			},
   863  		},
   864  		{
   865  			"multi-accesslogging",
   866  			[]config.Config{newTelemetry("default", multiAccessLoggingFilter)},
   867  			sidecar,
   868  			[]string{"envoy"},
   869  			[]LoggingConfig{
   870  				{
   871  					AccessLog: &accesslog.AccessLog{
   872  						Name:       wellknown.FileAccessLog,
   873  						ConfigType: &accesslog.AccessLog_TypedConfig{TypedConfig: protoconv.MessageToAny(defaultJSONLabelsOut)},
   874  					},
   875  					Provider: jsonTextProvider,
   876  					Filter: &tpb.AccessLogging_Filter{
   877  						Expression: "response.code >= 400",
   878  					},
   879  				},
   880  			},
   881  		},
   882  		{
   883  			"multi-accesslogging-nil",
   884  			[]config.Config{newTelemetry("default", multiAccessLoggingNilFilter)},
   885  			sidecar,
   886  			[]string{"envoy"},
   887  			[]LoggingConfig{
   888  				{
   889  					AccessLog: &accesslog.AccessLog{
   890  						Name:       wellknown.FileAccessLog,
   891  						ConfigType: &accesslog.AccessLog_TypedConfig{TypedConfig: protoconv.MessageToAny(defaultJSONLabelsOut)},
   892  					},
   893  					Provider: jsonTextProvider,
   894  				},
   895  			},
   896  		},
   897  		{
   898  			"server-and-client-different",
   899  			[]config.Config{newTelemetry("default", serverAndClientDifferent)},
   900  			sidecar,
   901  			[]string{"envoy"},
   902  			[]LoggingConfig{
   903  				{
   904  					AccessLog: &accesslog.AccessLog{
   905  						Name:       wellknown.FileAccessLog,
   906  						ConfigType: &accesslog.AccessLog_TypedConfig{TypedConfig: protoconv.MessageToAny(defaultJSONLabelsOut)},
   907  					},
   908  					Provider: jsonTextProvider,
   909  					Filter: &tpb.AccessLogging_Filter{
   910  						Expression: "response.code >= 500",
   911  					},
   912  				},
   913  			},
   914  		},
   915  	}
   916  	for _, tt := range tests {
   917  		t.Run(tt.name, func(t *testing.T) {
   918  			telemetry, ctx := createTestTelemetries(tt.cfgs, t)
   919  			telemetry.meshConfig.DefaultProviders.AccessLogging = tt.defaultProviders
   920  			got := telemetry.AccessLogging(ctx, tt.proxy, networking.ListenerClassSidecarOutbound, nil)
   921  			assert.Equal(t, tt.excepted, got)
   922  		})
   923  	}
   924  }
   925  
   926  func TestAccessLoggingCache(t *testing.T) {
   927  	sidecar := &Proxy{ConfigNamespace: "default", Metadata: &NodeMetadata{Labels: map[string]string{"app": "test"}}}
   928  	otherNamespace := &Proxy{ConfigNamespace: "common", Metadata: &NodeMetadata{Labels: map[string]string{"app": "test"}}}
   929  	cfgs := &tpb.Telemetry{
   930  		AccessLogging: []*tpb.AccessLogging{
   931  			{
   932  				Providers: []*tpb.ProviderRef{
   933  					{
   934  						Name: "envoy-json",
   935  					},
   936  				},
   937  				Filter: &tpb.AccessLogging_Filter{
   938  					Expression: "response.code >= 400",
   939  				},
   940  			},
   941  		},
   942  	}
   943  
   944  	telemetry, ctx := createTestTelemetries([]config.Config{newTelemetry("default", cfgs)}, t)
   945  	for _, s := range []*Proxy{sidecar, otherNamespace} {
   946  		t.Run(s.ConfigNamespace, func(t *testing.T) {
   947  			first := telemetry.AccessLogging(ctx, s, networking.ListenerClassSidecarOutbound, nil)
   948  			second := telemetry.AccessLogging(ctx, s, networking.ListenerClassSidecarOutbound, nil)
   949  			assert.Equal(t, first, second)
   950  		})
   951  	}
   952  }
   953  
   954  func TestBuildOpenTelemetryAccessLogConfig(t *testing.T) {
   955  	fakeCluster := "outbound|55680||otel-collector.monitoring.svc.cluster.local"
   956  	fakeAuthority := "otel-collector.monitoring.svc.cluster.local"
   957  	for _, tc := range []struct {
   958  		name        string
   959  		logName     string
   960  		clusterName string
   961  		hostname    string
   962  		body        string
   963  		labels      *structpb.Struct
   964  		expected    *otelaccesslog.OpenTelemetryAccessLogConfig
   965  	}{
   966  		{
   967  			name:        "default",
   968  			logName:     OtelEnvoyAccessLogFriendlyName,
   969  			clusterName: fakeCluster,
   970  			hostname:    fakeAuthority,
   971  			body:        EnvoyTextLogFormat,
   972  			expected: &otelaccesslog.OpenTelemetryAccessLogConfig{
   973  				CommonConfig: &grpcaccesslog.CommonGrpcAccessLogConfig{
   974  					LogName: OtelEnvoyAccessLogFriendlyName,
   975  					GrpcService: &core.GrpcService{
   976  						TargetSpecifier: &core.GrpcService_EnvoyGrpc_{
   977  							EnvoyGrpc: &core.GrpcService_EnvoyGrpc{
   978  								ClusterName: fakeCluster,
   979  								Authority:   fakeAuthority,
   980  							},
   981  						},
   982  					},
   983  					TransportApiVersion:     core.ApiVersion_V3,
   984  					FilterStateObjectsToLog: envoyWasmStateToLog,
   985  				},
   986  				DisableBuiltinLabels: true,
   987  				Body: &otlpcommon.AnyValue{
   988  					Value: &otlpcommon.AnyValue_StringValue{
   989  						StringValue: EnvoyTextLogFormat,
   990  					},
   991  				},
   992  			},
   993  		},
   994  		{
   995  			name:        "with attrs",
   996  			logName:     OtelEnvoyAccessLogFriendlyName,
   997  			clusterName: fakeCluster,
   998  			hostname:    fakeAuthority,
   999  			body:        EnvoyTextLogFormat,
  1000  			labels: &structpb.Struct{
  1001  				Fields: map[string]*structpb.Value{
  1002  					"protocol": {Kind: &structpb.Value_StringValue{StringValue: "%PROTOCOL%"}},
  1003  				},
  1004  			},
  1005  			expected: &otelaccesslog.OpenTelemetryAccessLogConfig{
  1006  				CommonConfig: &grpcaccesslog.CommonGrpcAccessLogConfig{
  1007  					LogName: OtelEnvoyAccessLogFriendlyName,
  1008  					GrpcService: &core.GrpcService{
  1009  						TargetSpecifier: &core.GrpcService_EnvoyGrpc_{
  1010  							EnvoyGrpc: &core.GrpcService_EnvoyGrpc{
  1011  								ClusterName: fakeCluster,
  1012  								Authority:   fakeAuthority,
  1013  							},
  1014  						},
  1015  					},
  1016  					TransportApiVersion:     core.ApiVersion_V3,
  1017  					FilterStateObjectsToLog: envoyWasmStateToLog,
  1018  				},
  1019  				DisableBuiltinLabels: true,
  1020  				Body: &otlpcommon.AnyValue{
  1021  					Value: &otlpcommon.AnyValue_StringValue{
  1022  						StringValue: EnvoyTextLogFormat,
  1023  					},
  1024  				},
  1025  				Attributes: &otlpcommon.KeyValueList{
  1026  					Values: []*otlpcommon.KeyValue{
  1027  						{
  1028  							Key:   "protocol",
  1029  							Value: &otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_StringValue{StringValue: "%PROTOCOL%"}},
  1030  						},
  1031  					},
  1032  				},
  1033  			},
  1034  		},
  1035  	} {
  1036  		t.Run(tc.name, func(t *testing.T) {
  1037  			got := buildOpenTelemetryAccessLogConfig(tc.logName, tc.hostname, tc.clusterName, tc.body, tc.labels)
  1038  			assert.Equal(t, tc.expected, got)
  1039  		})
  1040  	}
  1041  }
  1042  
  1043  func TestTelemetryAccessLogExhaustiveness(t *testing.T) {
  1044  	AssertProvidersHandled(telemetryAccessLogHandled)
  1045  }
  1046  
  1047  func TestTelemetryAccessLog(t *testing.T) {
  1048  	stdoutFormat := &meshconfig.MeshConfig_ExtensionProvider{
  1049  		Name: "stdout",
  1050  		Provider: &meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLog{
  1051  			EnvoyFileAccessLog: &meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLogProvider{
  1052  				Path: DevStdout,
  1053  			},
  1054  		},
  1055  	}
  1056  
  1057  	customTextFormat := &meshconfig.MeshConfig_ExtensionProvider{
  1058  		Name: "custom-text",
  1059  		Provider: &meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLog{
  1060  			EnvoyFileAccessLog: &meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLogProvider{
  1061  				Path: DevStdout,
  1062  				LogFormat: &meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLogProvider_LogFormat{
  1063  					LogFormat: &meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLogProvider_LogFormat_Text{
  1064  						Text: "%LOCAL_REPLY_BODY%:%RESPONSE_CODE%:path=%REQ(:path)%",
  1065  					},
  1066  				},
  1067  			},
  1068  		},
  1069  	}
  1070  
  1071  	customLabelsFormat := &meshconfig.MeshConfig_ExtensionProvider{
  1072  		Name: "custom-label",
  1073  		Provider: &meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLog{
  1074  			EnvoyFileAccessLog: &meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLogProvider{
  1075  				Path: DevStdout,
  1076  				LogFormat: &meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLogProvider_LogFormat{
  1077  					LogFormat: &meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLogProvider_LogFormat_Labels{
  1078  						Labels: &structpb.Struct{
  1079  							Fields: map[string]*structpb.Value{
  1080  								"start_time":                     {Kind: &structpb.Value_StringValue{StringValue: "%START_TIME%"}},
  1081  								"route_name":                     {Kind: &structpb.Value_StringValue{StringValue: "%ROUTE_NAME%"}},
  1082  								"method":                         {Kind: &structpb.Value_StringValue{StringValue: "%REQ(:METHOD)%"}},
  1083  								"path":                           {Kind: &structpb.Value_StringValue{StringValue: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%"}},
  1084  								"protocol":                       {Kind: &structpb.Value_StringValue{StringValue: "%PROTOCOL%"}},
  1085  								"response_code":                  {Kind: &structpb.Value_StringValue{StringValue: "%RESPONSE_CODE%"}},
  1086  								"response_flags":                 {Kind: &structpb.Value_StringValue{StringValue: "%RESPONSE_FLAGS%"}},
  1087  								"response_code_details":          {Kind: &structpb.Value_StringValue{StringValue: "%RESPONSE_CODE_DETAILS%"}},
  1088  								"connection_termination_details": {Kind: &structpb.Value_StringValue{StringValue: "%CONNECTION_TERMINATION_DETAILS%"}},
  1089  								"bytes_received":                 {Kind: &structpb.Value_StringValue{StringValue: "%BYTES_RECEIVED%"}},
  1090  								"bytes_sent":                     {Kind: &structpb.Value_StringValue{StringValue: "%BYTES_SENT%"}},
  1091  								"duration":                       {Kind: &structpb.Value_StringValue{StringValue: "%DURATION%"}},
  1092  								"upstream_service_time":          {Kind: &structpb.Value_StringValue{StringValue: "%RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)%"}},
  1093  								"x_forwarded_for":                {Kind: &structpb.Value_StringValue{StringValue: "%REQ(X-FORWARDED-FOR)%"}},
  1094  								"user_agent":                     {Kind: &structpb.Value_StringValue{StringValue: "%REQ(USER-AGENT)%"}},
  1095  								"request_id":                     {Kind: &structpb.Value_StringValue{StringValue: "%REQ(X-REQUEST-ID)%"}},
  1096  								"authority":                      {Kind: &structpb.Value_StringValue{StringValue: "%REQ(:AUTHORITY)%"}},
  1097  								"upstream_host":                  {Kind: &structpb.Value_StringValue{StringValue: "%UPSTREAM_HOST%"}},
  1098  								"upstream_cluster":               {Kind: &structpb.Value_StringValue{StringValue: "%UPSTREAM_CLUSTER%"}},
  1099  								"upstream_local_address":         {Kind: &structpb.Value_StringValue{StringValue: "%UPSTREAM_LOCAL_ADDRESS%"}},
  1100  								"downstream_local_address":       {Kind: &structpb.Value_StringValue{StringValue: "%DOWNSTREAM_LOCAL_ADDRESS%"}},
  1101  								"downstream_remote_address":      {Kind: &structpb.Value_StringValue{StringValue: "%DOWNSTREAM_REMOTE_ADDRESS%"}},
  1102  								"requested_server_name":          {Kind: &structpb.Value_StringValue{StringValue: "%REQUESTED_SERVER_NAME%"}},
  1103  							},
  1104  						},
  1105  					},
  1106  				},
  1107  			},
  1108  		},
  1109  	}
  1110  
  1111  	stderr := &meshconfig.MeshConfig_ExtensionProvider{
  1112  		Name: "stderr",
  1113  		Provider: &meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLog{
  1114  			EnvoyFileAccessLog: &meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLogProvider{
  1115  				Path: "/dev/stderr",
  1116  			},
  1117  		},
  1118  	}
  1119  
  1120  	fakeFilterStateObjects := []string{"fake-filter-state-object1", "fake-filter-state-object1"}
  1121  	grpcHTTPCfg := &meshconfig.MeshConfig_ExtensionProvider{
  1122  		Name: "grpc-http-als",
  1123  		Provider: &meshconfig.MeshConfig_ExtensionProvider_EnvoyHttpAls{
  1124  			EnvoyHttpAls: &meshconfig.MeshConfig_ExtensionProvider_EnvoyHttpGrpcV3LogProvider{
  1125  				LogName:                         "grpc-http-als",
  1126  				Service:                         "grpc-als.foo.svc.cluster.local",
  1127  				Port:                            9811,
  1128  				AdditionalRequestHeadersToLog:   []string{"fake-request-header1"},
  1129  				AdditionalResponseHeadersToLog:  []string{"fake-response-header1"},
  1130  				AdditionalResponseTrailersToLog: []string{"fake-response-trailer1"},
  1131  				FilterStateObjectsToLog:         fakeFilterStateObjects,
  1132  			},
  1133  		},
  1134  	}
  1135  
  1136  	grpcTCPCfg := &meshconfig.MeshConfig_ExtensionProvider{
  1137  		Name: "grpc-tcp-als",
  1138  		Provider: &meshconfig.MeshConfig_ExtensionProvider_EnvoyTcpAls{
  1139  			EnvoyTcpAls: &meshconfig.MeshConfig_ExtensionProvider_EnvoyTcpGrpcV3LogProvider{
  1140  				LogName:                 "grpc-tcp-als",
  1141  				Service:                 "grpc-als.foo.svc.cluster.local",
  1142  				Port:                    9811,
  1143  				FilterStateObjectsToLog: fakeFilterStateObjects,
  1144  			},
  1145  		},
  1146  	}
  1147  
  1148  	labels := &structpb.Struct{
  1149  		Fields: map[string]*structpb.Value{
  1150  			"protocol":   {Kind: &structpb.Value_StringValue{StringValue: "%PROTOCOL%"}},
  1151  			"start_time": {Kind: &structpb.Value_StringValue{StringValue: "%START_TIME%"}},
  1152  		},
  1153  	}
  1154  
  1155  	otelCfg := &meshconfig.MeshConfig_ExtensionProvider{
  1156  		Name: OtelEnvoyAccessLogFriendlyName,
  1157  		Provider: &meshconfig.MeshConfig_ExtensionProvider_EnvoyOtelAls{
  1158  			EnvoyOtelAls: &meshconfig.MeshConfig_ExtensionProvider_EnvoyOpenTelemetryLogProvider{
  1159  				Service: "otel.foo.svc.cluster.local",
  1160  				Port:    9811,
  1161  				LogFormat: &meshconfig.MeshConfig_ExtensionProvider_EnvoyOpenTelemetryLogProvider_LogFormat{
  1162  					Labels: labels,
  1163  				},
  1164  			},
  1165  		},
  1166  	}
  1167  
  1168  	defaultEnvoyProvider := &meshconfig.MeshConfig_ExtensionProvider{
  1169  		Name: "envoy",
  1170  		Provider: &meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLog{
  1171  			EnvoyFileAccessLog: &meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLogProvider{
  1172  				Path: "/dev/stdout",
  1173  			},
  1174  		},
  1175  	}
  1176  
  1177  	grpcBackendClusterName := "outbound|9811||grpc-als.foo.svc.cluster.local"
  1178  	grpcBackendAuthority := "grpc-als.foo.svc.cluster.local"
  1179  	otelAtrributeCfg := &otelaccesslog.OpenTelemetryAccessLogConfig{
  1180  		CommonConfig: &grpcaccesslog.CommonGrpcAccessLogConfig{
  1181  			LogName: OtelEnvoyAccessLogFriendlyName,
  1182  			GrpcService: &core.GrpcService{
  1183  				TargetSpecifier: &core.GrpcService_EnvoyGrpc_{
  1184  					EnvoyGrpc: &core.GrpcService_EnvoyGrpc{
  1185  						ClusterName: grpcBackendClusterName,
  1186  						Authority:   grpcBackendAuthority,
  1187  					},
  1188  				},
  1189  			},
  1190  			TransportApiVersion:     core.ApiVersion_V3,
  1191  			FilterStateObjectsToLog: envoyWasmStateToLog,
  1192  		},
  1193  		DisableBuiltinLabels: true,
  1194  		Body: &otlpcommon.AnyValue{
  1195  			Value: &otlpcommon.AnyValue_StringValue{
  1196  				StringValue: EnvoyTextLogFormat,
  1197  			},
  1198  		},
  1199  		Attributes: &otlpcommon.KeyValueList{
  1200  			Values: []*otlpcommon.KeyValue{
  1201  				{
  1202  					Key:   "protocol",
  1203  					Value: &otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_StringValue{StringValue: "%PROTOCOL%"}},
  1204  				},
  1205  				{
  1206  					Key:   "start_time",
  1207  					Value: &otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_StringValue{StringValue: "%START_TIME%"}},
  1208  				},
  1209  			},
  1210  		},
  1211  	}
  1212  
  1213  	clusterLookupFn = func(push *PushContext, service string, port int) (hostname string, cluster string, err error) {
  1214  		return grpcBackendAuthority, grpcBackendClusterName, nil
  1215  	}
  1216  
  1217  	stdout := &fileaccesslog.FileAccessLog{
  1218  		Path: DevStdout,
  1219  		AccessLogFormat: &fileaccesslog.FileAccessLog_LogFormat{
  1220  			LogFormat: &core.SubstitutionFormatString{
  1221  				Format: &core.SubstitutionFormatString_TextFormatSource{
  1222  					TextFormatSource: &core.DataSource{
  1223  						Specifier: &core.DataSource_InlineString{
  1224  							InlineString: EnvoyTextLogFormat,
  1225  						},
  1226  					},
  1227  				},
  1228  			},
  1229  		},
  1230  	}
  1231  
  1232  	customTextOut := &fileaccesslog.FileAccessLog{
  1233  		Path: DevStdout,
  1234  		AccessLogFormat: &fileaccesslog.FileAccessLog_LogFormat{
  1235  			LogFormat: &core.SubstitutionFormatString{
  1236  				Format: &core.SubstitutionFormatString_TextFormatSource{
  1237  					TextFormatSource: &core.DataSource{
  1238  						Specifier: &core.DataSource_InlineString{
  1239  							InlineString: "%LOCAL_REPLY_BODY%:%RESPONSE_CODE%:path=%REQ(:path)%\n",
  1240  						},
  1241  					},
  1242  				},
  1243  			},
  1244  		},
  1245  	}
  1246  
  1247  	customLabelsOut := &fileaccesslog.FileAccessLog{
  1248  		Path: DevStdout,
  1249  		AccessLogFormat: &fileaccesslog.FileAccessLog_LogFormat{
  1250  			LogFormat: &core.SubstitutionFormatString{
  1251  				Format: &core.SubstitutionFormatString_JsonFormat{
  1252  					JsonFormat: &structpb.Struct{
  1253  						Fields: map[string]*structpb.Value{
  1254  							"start_time":                     {Kind: &structpb.Value_StringValue{StringValue: "%START_TIME%"}},
  1255  							"route_name":                     {Kind: &structpb.Value_StringValue{StringValue: "%ROUTE_NAME%"}},
  1256  							"method":                         {Kind: &structpb.Value_StringValue{StringValue: "%REQ(:METHOD)%"}},
  1257  							"path":                           {Kind: &structpb.Value_StringValue{StringValue: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%"}},
  1258  							"protocol":                       {Kind: &structpb.Value_StringValue{StringValue: "%PROTOCOL%"}},
  1259  							"response_code":                  {Kind: &structpb.Value_StringValue{StringValue: "%RESPONSE_CODE%"}},
  1260  							"response_flags":                 {Kind: &structpb.Value_StringValue{StringValue: "%RESPONSE_FLAGS%"}},
  1261  							"response_code_details":          {Kind: &structpb.Value_StringValue{StringValue: "%RESPONSE_CODE_DETAILS%"}},
  1262  							"connection_termination_details": {Kind: &structpb.Value_StringValue{StringValue: "%CONNECTION_TERMINATION_DETAILS%"}},
  1263  							"bytes_received":                 {Kind: &structpb.Value_StringValue{StringValue: "%BYTES_RECEIVED%"}},
  1264  							"bytes_sent":                     {Kind: &structpb.Value_StringValue{StringValue: "%BYTES_SENT%"}},
  1265  							"duration":                       {Kind: &structpb.Value_StringValue{StringValue: "%DURATION%"}},
  1266  							"upstream_service_time":          {Kind: &structpb.Value_StringValue{StringValue: "%RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)%"}},
  1267  							"x_forwarded_for":                {Kind: &structpb.Value_StringValue{StringValue: "%REQ(X-FORWARDED-FOR)%"}},
  1268  							"user_agent":                     {Kind: &structpb.Value_StringValue{StringValue: "%REQ(USER-AGENT)%"}},
  1269  							"request_id":                     {Kind: &structpb.Value_StringValue{StringValue: "%REQ(X-REQUEST-ID)%"}},
  1270  							"authority":                      {Kind: &structpb.Value_StringValue{StringValue: "%REQ(:AUTHORITY)%"}},
  1271  							"upstream_host":                  {Kind: &structpb.Value_StringValue{StringValue: "%UPSTREAM_HOST%"}},
  1272  							"upstream_cluster":               {Kind: &structpb.Value_StringValue{StringValue: "%UPSTREAM_CLUSTER%"}},
  1273  							"upstream_local_address":         {Kind: &structpb.Value_StringValue{StringValue: "%UPSTREAM_LOCAL_ADDRESS%"}},
  1274  							"downstream_local_address":       {Kind: &structpb.Value_StringValue{StringValue: "%DOWNSTREAM_LOCAL_ADDRESS%"}},
  1275  							"downstream_remote_address":      {Kind: &structpb.Value_StringValue{StringValue: "%DOWNSTREAM_REMOTE_ADDRESS%"}},
  1276  							"requested_server_name":          {Kind: &structpb.Value_StringValue{StringValue: "%REQUESTED_SERVER_NAME%"}},
  1277  						},
  1278  					},
  1279  				},
  1280  				JsonFormatOptions: &core.JsonFormatOptions{SortProperties: true},
  1281  			},
  1282  		},
  1283  	}
  1284  
  1285  	stderrout := &fileaccesslog.FileAccessLog{
  1286  		Path: "/dev/stderr",
  1287  		AccessLogFormat: &fileaccesslog.FileAccessLog_LogFormat{
  1288  			LogFormat: &core.SubstitutionFormatString{
  1289  				Format: &core.SubstitutionFormatString_TextFormatSource{
  1290  					TextFormatSource: &core.DataSource{
  1291  						Specifier: &core.DataSource_InlineString{
  1292  							InlineString: EnvoyTextLogFormat,
  1293  						},
  1294  					},
  1295  				},
  1296  			},
  1297  		},
  1298  	}
  1299  
  1300  	grpcHTTPout := &grpcaccesslog.HttpGrpcAccessLogConfig{
  1301  		CommonConfig: &grpcaccesslog.CommonGrpcAccessLogConfig{
  1302  			LogName: "grpc-http-als",
  1303  			GrpcService: &core.GrpcService{
  1304  				TargetSpecifier: &core.GrpcService_EnvoyGrpc_{
  1305  					EnvoyGrpc: &core.GrpcService_EnvoyGrpc{
  1306  						ClusterName: grpcBackendClusterName,
  1307  						Authority:   grpcBackendAuthority,
  1308  					},
  1309  				},
  1310  			},
  1311  			TransportApiVersion:     core.ApiVersion_V3,
  1312  			FilterStateObjectsToLog: fakeFilterStateObjects,
  1313  		},
  1314  		AdditionalRequestHeadersToLog:   []string{"fake-request-header1"},
  1315  		AdditionalResponseHeadersToLog:  []string{"fake-response-header1"},
  1316  		AdditionalResponseTrailersToLog: []string{"fake-response-trailer1"},
  1317  	}
  1318  
  1319  	grpcTCPOut := &grpcaccesslog.TcpGrpcAccessLogConfig{
  1320  		CommonConfig: &grpcaccesslog.CommonGrpcAccessLogConfig{
  1321  			LogName: "grpc-tcp-als",
  1322  			GrpcService: &core.GrpcService{
  1323  				TargetSpecifier: &core.GrpcService_EnvoyGrpc_{
  1324  					EnvoyGrpc: &core.GrpcService_EnvoyGrpc{
  1325  						ClusterName: grpcBackendClusterName,
  1326  						Authority:   grpcBackendAuthority,
  1327  					},
  1328  				},
  1329  			},
  1330  			TransportApiVersion:     core.ApiVersion_V3,
  1331  			FilterStateObjectsToLog: fakeFilterStateObjects,
  1332  		},
  1333  	}
  1334  
  1335  	defaultFormatJSON, _ := protomarshal.ToJSON(EnvoyJSONLogFormatIstio)
  1336  
  1337  	ctx := NewPushContext()
  1338  	ctx.ServiceIndex.HostnameAndNamespace["otel-collector.foo.svc.cluster.local"] = map[string]*Service{
  1339  		"foo": {
  1340  			Hostname:       "otel-collector.foo.svc.cluster.local",
  1341  			DefaultAddress: "172.217.0.0/16",
  1342  			Ports: PortList{
  1343  				&Port{
  1344  					Name:     "grpc-port",
  1345  					Port:     3417,
  1346  					Protocol: protocol.TCP,
  1347  				},
  1348  				&Port{
  1349  					Name:     "http-port",
  1350  					Port:     3418,
  1351  					Protocol: protocol.HTTP,
  1352  				},
  1353  			},
  1354  			Resolution: ClientSideLB,
  1355  			Attributes: ServiceAttributes{
  1356  				Name:            "otel-collector",
  1357  				Namespace:       "foo",
  1358  				ServiceRegistry: provider.Kubernetes,
  1359  			},
  1360  		},
  1361  	}
  1362  
  1363  	for _, tc := range []struct {
  1364  		name       string
  1365  		ctx        *PushContext
  1366  		meshConfig *meshconfig.MeshConfig
  1367  		fp         *meshconfig.MeshConfig_ExtensionProvider
  1368  		expected   *accesslog.AccessLog
  1369  	}{
  1370  		{
  1371  			name: "stdout",
  1372  			meshConfig: &meshconfig.MeshConfig{
  1373  				AccessLogEncoding: meshconfig.MeshConfig_TEXT,
  1374  			},
  1375  			fp: stdoutFormat,
  1376  			expected: &accesslog.AccessLog{
  1377  				Name:       wellknown.FileAccessLog,
  1378  				ConfigType: &accesslog.AccessLog_TypedConfig{TypedConfig: protoconv.MessageToAny(stdout)},
  1379  			},
  1380  		},
  1381  		{
  1382  			name: "stderr",
  1383  			meshConfig: &meshconfig.MeshConfig{
  1384  				AccessLogEncoding: meshconfig.MeshConfig_TEXT,
  1385  			},
  1386  			fp: stderr,
  1387  			expected: &accesslog.AccessLog{
  1388  				Name:       wellknown.FileAccessLog,
  1389  				ConfigType: &accesslog.AccessLog_TypedConfig{TypedConfig: protoconv.MessageToAny(stderrout)},
  1390  			},
  1391  		},
  1392  		{
  1393  			name: "custom-text",
  1394  			meshConfig: &meshconfig.MeshConfig{
  1395  				AccessLogEncoding: meshconfig.MeshConfig_TEXT,
  1396  			},
  1397  			fp: customTextFormat,
  1398  			expected: &accesslog.AccessLog{
  1399  				Name:       wellknown.FileAccessLog,
  1400  				ConfigType: &accesslog.AccessLog_TypedConfig{TypedConfig: protoconv.MessageToAny(customTextOut)},
  1401  			},
  1402  		},
  1403  		{
  1404  			name: "default-labels",
  1405  			meshConfig: &meshconfig.MeshConfig{
  1406  				AccessLogEncoding: meshconfig.MeshConfig_TEXT,
  1407  			},
  1408  			fp: jsonTextProvider,
  1409  			expected: &accesslog.AccessLog{
  1410  				Name:       wellknown.FileAccessLog,
  1411  				ConfigType: &accesslog.AccessLog_TypedConfig{TypedConfig: protoconv.MessageToAny(defaultJSONLabelsOut)},
  1412  			},
  1413  		},
  1414  		{
  1415  			name: "custom-labels",
  1416  			meshConfig: &meshconfig.MeshConfig{
  1417  				AccessLogEncoding: meshconfig.MeshConfig_TEXT,
  1418  			},
  1419  			fp: customLabelsFormat,
  1420  			expected: &accesslog.AccessLog{
  1421  				Name:       wellknown.FileAccessLog,
  1422  				ConfigType: &accesslog.AccessLog_TypedConfig{TypedConfig: protoconv.MessageToAny(customLabelsOut)},
  1423  			},
  1424  		},
  1425  		{
  1426  			name: "otel",
  1427  			ctx:  ctx,
  1428  			meshConfig: &meshconfig.MeshConfig{
  1429  				AccessLogEncoding: meshconfig.MeshConfig_TEXT,
  1430  			},
  1431  			fp: otelCfg,
  1432  			expected: &accesslog.AccessLog{
  1433  				Name:       OtelEnvoyALSName,
  1434  				ConfigType: &accesslog.AccessLog_TypedConfig{TypedConfig: protoconv.MessageToAny(otelAtrributeCfg)},
  1435  			},
  1436  		},
  1437  		{
  1438  			name: "grpc-http",
  1439  			fp:   grpcHTTPCfg,
  1440  			meshConfig: &meshconfig.MeshConfig{
  1441  				AccessLogEncoding: meshconfig.MeshConfig_TEXT,
  1442  			},
  1443  			expected: &accesslog.AccessLog{
  1444  				Name:       wellknown.HTTPGRPCAccessLog,
  1445  				ConfigType: &accesslog.AccessLog_TypedConfig{TypedConfig: protoconv.MessageToAny(grpcHTTPout)},
  1446  			},
  1447  		},
  1448  		{
  1449  			name: "grpc-tcp",
  1450  			fp:   grpcTCPCfg,
  1451  			meshConfig: &meshconfig.MeshConfig{
  1452  				AccessLogEncoding: meshconfig.MeshConfig_TEXT,
  1453  			},
  1454  			expected: &accesslog.AccessLog{
  1455  				Name:       TCPEnvoyALSName,
  1456  				ConfigType: &accesslog.AccessLog_TypedConfig{TypedConfig: protoconv.MessageToAny(grpcTCPOut)},
  1457  			},
  1458  		},
  1459  		{
  1460  			name: "builtin-fallback",
  1461  			ctx:  ctx,
  1462  			meshConfig: &meshconfig.MeshConfig{
  1463  				AccessLogEncoding: meshconfig.MeshConfig_JSON,
  1464  				AccessLogFormat:   defaultFormatJSON,
  1465  			},
  1466  			fp: defaultEnvoyProvider,
  1467  			expected: &accesslog.AccessLog{
  1468  				Name:       wellknown.FileAccessLog,
  1469  				ConfigType: &accesslog.AccessLog_TypedConfig{TypedConfig: protoconv.MessageToAny(defaultJSONLabelsOut)},
  1470  			},
  1471  		},
  1472  		{
  1473  			name: "builtin-not-fallback",
  1474  			ctx:  ctx,
  1475  			meshConfig: &meshconfig.MeshConfig{
  1476  				AccessLogEncoding: meshconfig.MeshConfig_JSON,
  1477  				AccessLogFormat:   defaultFormatJSON,
  1478  			},
  1479  			fp: &meshconfig.MeshConfig_ExtensionProvider{
  1480  				Name: "envoy",
  1481  				Provider: &meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLog{
  1482  					EnvoyFileAccessLog: &meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLogProvider{
  1483  						Path: "/dev/stdout",
  1484  						LogFormat: &meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLogProvider_LogFormat{
  1485  							LogFormat: &meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLogProvider_LogFormat_Text{
  1486  								Text: "%LOCAL_REPLY_BODY%:%RESPONSE_CODE%:path=%REQ(:path)%",
  1487  							},
  1488  						},
  1489  					},
  1490  				},
  1491  			},
  1492  			expected: &accesslog.AccessLog{
  1493  				Name: wellknown.FileAccessLog,
  1494  				ConfigType: &accesslog.AccessLog_TypedConfig{TypedConfig: protoconv.MessageToAny(&fileaccesslog.FileAccessLog{
  1495  					Path: DevStdout,
  1496  					AccessLogFormat: &fileaccesslog.FileAccessLog_LogFormat{
  1497  						LogFormat: &core.SubstitutionFormatString{
  1498  							Format: &core.SubstitutionFormatString_TextFormatSource{
  1499  								TextFormatSource: &core.DataSource{
  1500  									Specifier: &core.DataSource_InlineString{
  1501  										InlineString: "%LOCAL_REPLY_BODY%:%RESPONSE_CODE%:path=%REQ(:path)%\n",
  1502  									},
  1503  								},
  1504  							},
  1505  						},
  1506  					},
  1507  				})},
  1508  			},
  1509  		},
  1510  	} {
  1511  		t.Run(tc.name, func(t *testing.T) {
  1512  			push := tc.ctx
  1513  			if push == nil {
  1514  				push = NewPushContext()
  1515  			}
  1516  			push.Mesh = tc.meshConfig
  1517  
  1518  			got := telemetryAccessLog(push, tc.fp)
  1519  			if got == nil {
  1520  				t.Fatalf("get nil accesslog")
  1521  			}
  1522  			assert.Equal(t, tc.expected, got)
  1523  		})
  1524  	}
  1525  }
  1526  
  1527  func TestAccessLogJSONFormatters(t *testing.T) {
  1528  	cases := []struct {
  1529  		name     string
  1530  		json     *structpb.Struct
  1531  		expected []*core.TypedExtensionConfig
  1532  	}{
  1533  		{
  1534  			name:     "default",
  1535  			json:     EnvoyJSONLogFormatIstio,
  1536  			expected: []*core.TypedExtensionConfig{},
  1537  		},
  1538  		{
  1539  			name: "with-req-without-query",
  1540  			json: &structpb.Struct{
  1541  				Fields: map[string]*structpb.Value{
  1542  					"key1": {Kind: &structpb.Value_StringValue{StringValue: "%REQ_WITHOUT_QUERY(key1:val1)%"}},
  1543  				},
  1544  			},
  1545  			expected: []*core.TypedExtensionConfig{
  1546  				reqWithoutQueryFormatter,
  1547  			},
  1548  		},
  1549  		{
  1550  			name: "with-metadata",
  1551  			json: &structpb.Struct{
  1552  				Fields: map[string]*structpb.Value{
  1553  					"key1": {Kind: &structpb.Value_StringValue{StringValue: "%METADATA(CLUSTER:istio)%"}},
  1554  				},
  1555  			},
  1556  			expected: []*core.TypedExtensionConfig{
  1557  				metadataFormatter,
  1558  			},
  1559  		},
  1560  		{
  1561  			name: "with-both",
  1562  			json: &structpb.Struct{
  1563  				Fields: map[string]*structpb.Value{
  1564  					"key1": {Kind: &structpb.Value_StringValue{StringValue: "%REQ_WITHOUT_QUERY(key1:val1)%"}},
  1565  					"key2": {Kind: &structpb.Value_StringValue{StringValue: "%METADATA(UPSTREAM_HOST:istio)%"}},
  1566  				},
  1567  			},
  1568  			expected: []*core.TypedExtensionConfig{
  1569  				reqWithoutQueryFormatter,
  1570  				metadataFormatter,
  1571  			},
  1572  		},
  1573  		{
  1574  			name: "with-multi-metadata",
  1575  			json: &structpb.Struct{
  1576  				Fields: map[string]*structpb.Value{
  1577  					"key1": {Kind: &structpb.Value_StringValue{StringValue: "%METADATA(CLUSTER:istio)%"}},
  1578  					"key2": {Kind: &structpb.Value_StringValue{StringValue: "%METADATA(UPSTREAM_HOST:istio)%"}},
  1579  				},
  1580  			},
  1581  			expected: []*core.TypedExtensionConfig{
  1582  				metadataFormatter,
  1583  			},
  1584  		},
  1585  		{
  1586  			name: "more-complex",
  1587  			json: &structpb.Struct{
  1588  				Fields: map[string]*structpb.Value{
  1589  					"req1": {Kind: &structpb.Value_StringValue{StringValue: "%REQ_WITHOUT_QUERY(key1:val1)%"}},
  1590  					"req2": {Kind: &structpb.Value_StringValue{StringValue: "%REQ_WITHOUT_QUERY(key2:val1)%"}},
  1591  					"key1": {Kind: &structpb.Value_StringValue{StringValue: "%METADATA(CLUSTER:istio)%"}},
  1592  					"key2": {Kind: &structpb.Value_StringValue{StringValue: "%METADATA(UPSTREAM_HOST:istio)%"}},
  1593  				},
  1594  			},
  1595  			expected: []*core.TypedExtensionConfig{
  1596  				reqWithoutQueryFormatter,
  1597  				metadataFormatter,
  1598  			},
  1599  		},
  1600  	}
  1601  
  1602  	for _, tc := range cases {
  1603  		t.Run(tc.name, func(t *testing.T) {
  1604  			got := accessLogJSONFormatters(tc.json)
  1605  			assert.Equal(t, tc.expected, got)
  1606  		})
  1607  	}
  1608  }
  1609  
  1610  func TestAccessLogTextFormatters(t *testing.T) {
  1611  	cases := []struct {
  1612  		name     string
  1613  		text     string
  1614  		expected []*core.TypedExtensionConfig
  1615  	}{
  1616  		{
  1617  			name:     "default",
  1618  			text:     EnvoyTextLogFormat,
  1619  			expected: []*core.TypedExtensionConfig{},
  1620  		},
  1621  		{
  1622  			name: "with-req-without-query",
  1623  			text: EnvoyTextLogFormat + " %REQ_WITHOUT_QUERY(key1:val1)%",
  1624  			expected: []*core.TypedExtensionConfig{
  1625  				reqWithoutQueryFormatter,
  1626  			},
  1627  		},
  1628  		{
  1629  			name: "with-metadata",
  1630  			text: EnvoyTextLogFormat + " %METADATA(CLUSTER:istio)%",
  1631  			expected: []*core.TypedExtensionConfig{
  1632  				metadataFormatter,
  1633  			},
  1634  		},
  1635  		{
  1636  			name: "with-both",
  1637  			text: EnvoyTextLogFormat + " %REQ_WITHOUT_QUERY(key1:val1)% %METADATA(CLUSTER:istio)%",
  1638  			expected: []*core.TypedExtensionConfig{
  1639  				reqWithoutQueryFormatter,
  1640  				metadataFormatter,
  1641  			},
  1642  		},
  1643  		{
  1644  			name: "with-multi-metadata",
  1645  			text: EnvoyTextLogFormat + " %METADATA(UPSTREAM_HOST:istio)% %METADATA(CLUSTER:istio)%",
  1646  			expected: []*core.TypedExtensionConfig{
  1647  				metadataFormatter,
  1648  			},
  1649  		},
  1650  		{
  1651  			name: "more-complex",
  1652  			text: EnvoyTextLogFormat + " %REQ_WITHOUT_QUERY(key1:val1)% REQ_WITHOUT_QUERY(key2:val1)% %METADATA(UPSTREAM_HOST:istio)% %METADATA(CLUSTER:istio)%",
  1653  			expected: []*core.TypedExtensionConfig{
  1654  				reqWithoutQueryFormatter,
  1655  				metadataFormatter,
  1656  			},
  1657  		},
  1658  	}
  1659  
  1660  	for _, tc := range cases {
  1661  		t.Run(tc.name, func(t *testing.T) {
  1662  			got := accessLogTextFormatters(tc.text)
  1663  			assert.Equal(t, tc.expected, got)
  1664  		})
  1665  	}
  1666  }
  1667  
  1668  func TestTelemetryAccessLogWithFormatter(t *testing.T) {
  1669  	sidecar := &Proxy{
  1670  		ConfigNamespace: "default",
  1671  		Labels:          map[string]string{"app": "test"},
  1672  		Metadata:        &NodeMetadata{},
  1673  	}
  1674  
  1675  	textFormatters := &tpb.Telemetry{
  1676  		AccessLogging: []*tpb.AccessLogging{
  1677  			{
  1678  				Providers: []*tpb.ProviderRef{
  1679  					{
  1680  						Name: "envoy-text-formatters",
  1681  					},
  1682  				},
  1683  			},
  1684  		},
  1685  	}
  1686  
  1687  	jsonFormatters := &tpb.Telemetry{
  1688  		AccessLogging: []*tpb.AccessLogging{
  1689  			{
  1690  				Providers: []*tpb.ProviderRef{
  1691  					{
  1692  						Name: "envoy-json-formatters",
  1693  					},
  1694  				},
  1695  			},
  1696  		},
  1697  	}
  1698  
  1699  	tests := []struct {
  1700  		name             string
  1701  		cfgs             []config.Config
  1702  		proxy            *Proxy
  1703  		defaultProviders []string
  1704  		excepted         []LoggingConfig
  1705  	}{
  1706  		{
  1707  			"text",
  1708  			[]config.Config{newTelemetry("default", textFormatters)},
  1709  			sidecar,
  1710  			[]string{},
  1711  			[]LoggingConfig{
  1712  				{
  1713  					AccessLog: &accesslog.AccessLog{
  1714  						Name:       wellknown.FileAccessLog,
  1715  						ConfigType: &accesslog.AccessLog_TypedConfig{TypedConfig: protoconv.MessageToAny(formattersTextLabelsOut)},
  1716  					},
  1717  					Provider: textFormattersProvider,
  1718  				},
  1719  			},
  1720  		},
  1721  		{
  1722  			"json",
  1723  			[]config.Config{newTelemetry("default", jsonFormatters)},
  1724  			sidecar,
  1725  			[]string{},
  1726  			[]LoggingConfig{
  1727  				{
  1728  					AccessLog: &accesslog.AccessLog{
  1729  						Name:       wellknown.FileAccessLog,
  1730  						ConfigType: &accesslog.AccessLog_TypedConfig{TypedConfig: protoconv.MessageToAny(formattersJSONLabelsOut)},
  1731  					},
  1732  					Provider: jsonFormattersProvider,
  1733  				},
  1734  			},
  1735  		},
  1736  	}
  1737  	for _, tt := range tests {
  1738  		t.Run(tt.name, func(t *testing.T) {
  1739  			telemetry, ctx := createTestTelemetries(tt.cfgs, t)
  1740  			telemetry.meshConfig.DefaultProviders.AccessLogging = tt.defaultProviders
  1741  			got := telemetry.AccessLogging(ctx, tt.proxy, networking.ListenerClassSidecarOutbound, nil)
  1742  			assert.Equal(t, tt.excepted, got)
  1743  		})
  1744  	}
  1745  }