Skip to content

Commit 5e41c6b

Browse files
authored
[exporter/sumologic]: add sticky session (#33011)
**Description:** Adds support for sticky session in order to better support AWS LB. This code is moved from Sumo Logic repository **Link to tracking Issue:** #32315 **Testing:** Tested manually **Documentation:** N/A --------- Signed-off-by: Dominik Rosiek <[email protected]>
1 parent d43a904 commit 5e41c6b

File tree

7 files changed

+133
-25
lines changed

7 files changed

+133
-25
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: enhancement
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: sumologicexporter
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: add sticky session support
11+
12+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
13+
issues: [32315]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext:
19+
20+
# If your change doesn't affect end users or the exported elements of any package,
21+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
22+
# Optional: The change log or logs in which this entry should be included.
23+
# e.g. '[user]' or '[user, api]'
24+
# Include 'user' if the change is relevant to end users.
25+
# Include 'api' if there is a change to a library API.
26+
# Default: '[user]'
27+
change_logs: [user]

exporter/sumologicexporter/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,10 @@ exporters:
147147
# maximum connection timeout is 55s, default = 5s
148148
timeout: <timeout>
149149

150+
# defines if sticky session support is enable.
151+
# default=false
152+
sticky_session_enabled: {true, false}
153+
150154
# for below described queueing and retry related configuration please refer to:
151155
# https://github.com/open-telemetry/opentelemetry-collector/blob/main/exporter/exporterhelper/README.md#configuration
152156

exporter/sumologicexporter/config.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ type Config struct {
6464
SourceHost string `mapstructure:"source_host"`
6565
// Name of the client
6666
Client string `mapstructure:"client"`
67+
68+
// StickySessionEnabled defines if sticky session support is enable.
69+
// By default this is false.
70+
StickySessionEnabled bool `mapstructure:"sticky_session_enabled"`
6771
}
6872

6973
// createDefaultClientConfig returns default http client settings
@@ -132,8 +136,10 @@ const (
132136
DefaultClient string = "otelcol"
133137
// DefaultLogKey defines default LogKey value
134138
DefaultLogKey string = "log"
135-
// DefaultGraphiteTemplate defines default template for Graphite
136-
DefaultGraphiteTemplate string = "%{_metric_}"
139+
// DefaultDropRoutingAttribute defines default DropRoutingAttribute
140+
DefaultDropRoutingAttribute string = ""
141+
// DefaultStickySessionEnabled defines default StickySessionEnabled value
142+
DefaultStickySessionEnabled bool = false
137143
)
138144

139145
func (cfg *Config) Validate() error {

exporter/sumologicexporter/exporter.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ type sumologicexporter struct {
5454
foundSumologicExtension bool
5555
sumologicExtension *sumologicextension.SumologicExtension
5656

57+
stickySessionCookieLock sync.RWMutex
58+
stickySessionCookie string
59+
5760
id component.ID
5861
}
5962

@@ -289,6 +292,8 @@ func (se *sumologicexporter) pushLogsData(ctx context.Context, ld plog.Logs) err
289292
metricsURL,
290293
logsURL,
291294
tracesURL,
295+
se.StickySessionCookie,
296+
se.SetStickySessionCookie,
292297
se.id,
293298
)
294299

@@ -366,6 +371,8 @@ func (se *sumologicexporter) pushMetricsData(ctx context.Context, md pmetric.Met
366371
metricsURL,
367372
logsURL,
368373
tracesURL,
374+
se.StickySessionCookie,
375+
se.SetStickySessionCookie,
369376
se.id,
370377
)
371378

@@ -406,6 +413,27 @@ func (se *sumologicexporter) handleUnauthorizedErrors(ctx context.Context, errs
406413
}
407414
}
408415

416+
func (se *sumologicexporter) StickySessionCookie() string {
417+
if se.foundSumologicExtension {
418+
return se.sumologicExtension.StickySessionCookie()
419+
}
420+
421+
se.stickySessionCookieLock.RLock()
422+
defer se.stickySessionCookieLock.RUnlock()
423+
return se.stickySessionCookie
424+
}
425+
426+
func (se *sumologicexporter) SetStickySessionCookie(stickySessionCookie string) {
427+
if se.foundSumologicExtension {
428+
se.sumologicExtension.SetStickySessionCookie(stickySessionCookie)
429+
return
430+
}
431+
432+
se.stickySessionCookieLock.Lock()
433+
se.stickySessionCookie = stickySessionCookie
434+
se.stickySessionCookieLock.Unlock()
435+
}
436+
409437
// get the destination url for a given signal type
410438
// this mostly adds signal-specific suffixes if the format is otlp
411439
func getSignalURL(oCfg *Config, endpointURL string, signal component.DataType) (string, error) {

exporter/sumologicexporter/factory.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,10 @@ func createDefaultConfig() component.Config {
4040
SourceHost: DefaultSourceHost,
4141
Client: DefaultClient,
4242

43-
ClientConfig: createDefaultClientConfig(),
44-
BackOffConfig: configretry.NewDefaultBackOffConfig(),
45-
QueueSettings: qs,
43+
ClientConfig: createDefaultClientConfig(),
44+
BackOffConfig: configretry.NewDefaultBackOffConfig(),
45+
QueueSettings: qs,
46+
StickySessionEnabled: DefaultStickySessionEnabled,
4647
}
4748
}
4849

exporter/sumologicexporter/sender.go

Lines changed: 60 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -110,16 +110,18 @@ func (b *bodyBuilder) toCountingReader() *countingReader {
110110
}
111111

112112
type sender struct {
113-
logger *zap.Logger
114-
config *Config
115-
client *http.Client
116-
filter filter
117-
sources sourceFormats
118-
prometheusFormatter prometheusFormatter
119-
dataURLMetrics string
120-
dataURLLogs string
121-
dataURLTraces string
122-
id component.ID
113+
logger *zap.Logger
114+
config *Config
115+
client *http.Client
116+
filter filter
117+
sources sourceFormats
118+
prometheusFormatter prometheusFormatter
119+
dataURLMetrics string
120+
dataURLLogs string
121+
dataURLTraces string
122+
stickySessionCookieFunc func() string
123+
setStickySessionCookieFunc func(string)
124+
id component.ID
123125
}
124126

125127
const (
@@ -140,6 +142,7 @@ const (
140142
contentTypeLogs string = "application/x-www-form-urlencoded"
141143
contentTypePrometheus string = "application/vnd.sumologic.prometheus"
142144
contentTypeOTLP string = "application/x-protobuf"
145+
stickySessionKey string = "AWSALB"
143146
)
144147

145148
func newSender(
@@ -152,19 +155,23 @@ func newSender(
152155
metricsURL string,
153156
logsURL string,
154157
tracesURL string,
158+
stickySessionCookieFunc func() string,
159+
setStickySessionCookieFunc func(string),
155160
id component.ID,
156161
) *sender {
157162
return &sender{
158-
logger: logger,
159-
config: cfg,
160-
client: cl,
161-
filter: f,
162-
sources: s,
163-
prometheusFormatter: pf,
164-
dataURLMetrics: metricsURL,
165-
dataURLLogs: logsURL,
166-
dataURLTraces: tracesURL,
167-
id: id,
163+
logger: logger,
164+
config: cfg,
165+
client: cl,
166+
filter: f,
167+
sources: s,
168+
prometheusFormatter: pf,
169+
dataURLMetrics: metricsURL,
170+
dataURLLogs: logsURL,
171+
dataURLTraces: tracesURL,
172+
stickySessionCookieFunc: stickySessionCookieFunc,
173+
setStickySessionCookieFunc: setStickySessionCookieFunc,
174+
id: id,
168175
}
169176
}
170177

@@ -181,6 +188,10 @@ func (s *sender) send(ctx context.Context, pipeline PipelineType, reader *counti
181188
return err
182189
}
183190

191+
if s.config.StickySessionEnabled {
192+
s.addStickySessionCookie(req)
193+
}
194+
184195
s.logger.Debug("Sending data",
185196
zap.String("pipeline", string(pipeline)),
186197
zap.Any("headers", req.Header),
@@ -200,6 +211,10 @@ func (s *sender) send(ctx context.Context, pipeline PipelineType, reader *counti
200211
}
201212

202213
func (s *sender) handleReceiverResponse(resp *http.Response) error {
214+
if s.config.StickySessionEnabled {
215+
s.updateStickySessionCookie(resp)
216+
}
217+
203218
// API responds with a 200 or 204 with ConentLength set to 0 when all data
204219
// has been successfully ingested.
205220
if resp.ContentLength == 0 && (resp.StatusCode == 200 || resp.StatusCode == 204) {
@@ -684,3 +699,28 @@ func (s *sender) recordMetrics(duration time.Duration, count int64, req *http.Re
684699
s.logger.Debug("error for recording metric for sent request", zap.Error(err))
685700
}
686701
}
702+
703+
func (s *sender) addStickySessionCookie(req *http.Request) {
704+
currectCookieValue := s.stickySessionCookieFunc()
705+
if currectCookieValue != "" {
706+
cookie := &http.Cookie{
707+
Name: stickySessionKey,
708+
Value: currectCookieValue,
709+
}
710+
req.AddCookie(cookie)
711+
}
712+
}
713+
714+
func (s *sender) updateStickySessionCookie(resp *http.Response) {
715+
cookies := resp.Cookies()
716+
if len(cookies) > 0 {
717+
for _, cookie := range cookies {
718+
if cookie.Name == stickySessionKey {
719+
if cookie.Value != s.stickySessionCookieFunc() {
720+
s.setStickySessionCookieFunc(cookie.Value)
721+
}
722+
return
723+
}
724+
}
725+
}
726+
}

exporter/sumologicexporter/sender_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ func prepareSenderTest(t *testing.T, compression configcompression.Type, cb []fu
114114
testServer.URL,
115115
testServer.URL,
116116
testServer.URL,
117+
func() string { return "" },
118+
func(string) {},
117119
component.ID{},
118120
),
119121
}

0 commit comments

Comments
 (0)