Skip to content

Commit e412859

Browse files
authored
fix: requests error handling (#82)
- added locally built docker build-image - fixed retries for 5xx errors - fixed various leftover build issues LOG-11814
1 parent 6d5d432 commit e412859

7 files changed

Lines changed: 653 additions & 477 deletions

File tree

Dockerfile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
FROM condaforge/miniforge3:4.12.0-0
2+
3+
RUN conda install -y gcc pip poetry=1.1.7 git
4+
RUN mkdir /workdir && chmod 777 /workdir
5+
RUN git config --global --add safe.directory /workdir
6+
WORKDIR /workdir
7+

Jenkinsfile

100644100755
Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@ def DEFAULT_BRANCH = 'master'
55
def CURRENT_BRANCH = [env.CHANGE_BRANCH, env.BRANCH_NAME]?.find{branch -> branch != null}
66

77
pipeline {
8-
agent none
8+
agent {
9+
node {
10+
label 'ec2-fleet'
11+
customWorkspace "${PROJECT_NAME}-${BUILD_NUMBER}"
12+
}
13+
}
914

1015
options {
1116
timestamps()
@@ -18,12 +23,6 @@ pipeline {
1823

1924
stages {
2025
stage('Test') {
21-
agent {
22-
node {
23-
label 'ec2-fleet'
24-
customWorkspace "${PROJECT_NAME}-${BUILD_NUMBER}"
25-
}
26-
}
2726

2827
steps {
2928
sh 'make install lint test'
@@ -45,12 +44,6 @@ pipeline {
4544
}
4645

4746
stage('Release') {
48-
agent {
49-
node {
50-
label 'ec2-fleet'
51-
customWorkspace "${PROJECT_NAME}-${BUILD_NUMBER}"
52-
}
53-
}
5447

5548
stages {
5649
stage('dry run') {

Makefile

100644100755
Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ include .config.mk
77
DOCKER = docker
88
DOCKER_RUN := $(DOCKER) run --rm -i
99
WORKDIR :=/workdir
10-
DOCKER_COMMAND := $(DOCKER_RUN) -v $(PWD):$(WORKDIR):Z -w $(WORKDIR) \
10+
DOCKER_COMMAND := $(DOCKER_RUN) -u "$(shell id -u)":"$(shell id -g)" -v $(PWD):$(WORKDIR):Z -w $(WORKDIR) \
1111
-e XDG_CONFIG_HOME=$(WORKDIR) \
1212
-e XDG_CACHE_HOME=$(WORKDIR) \
1313
-e POETRY_CACHE_DIR=$(WORKDIR)/.cache \
@@ -21,13 +21,19 @@ DOCKER_COMMAND := $(DOCKER_RUN) -v $(PWD):$(WORKDIR):Z -w $(WORKDIR) \
2121
-e GIT_AUTHOR_EMAIL \
2222
-e GIT_COMMITTER_NAME \
2323
-e GIT_COMMITTER_EMAIL \
24-
us.gcr.io/logdna-k8s/python:3.7-ci
24+
logdna-poetry:local
25+
2526

2627
POETRY_COMMAND := $(DOCKER_COMMAND) poetry
2728

2829
# Exports the variables for shell use
2930
export
3031

32+
# build image
33+
.PHONY:build-image
34+
build-image:
35+
DOCKER_BUILDKIT=1 $(DOCKER) build -t logdna-poetry:local .
36+
3137
# This helper function makes debugging much easier.
3238
.PHONY:debug-%
3339
debug-%: ## Debug a variable by calling `make debug-VARIABLE`
@@ -39,30 +45,31 @@ help: ## Show this help, includes list of all actions.
3945
@awk 'BEGIN {FS = ":.*?## "}; /^.+: .*?## / && !/awk/ {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' ${MAKEFILE_LIST}
4046

4147
.PHONY:run
42-
run: ## purge build time artifacts
48+
run: install ## purge build time artifacts
4349
$(DOCKER_COMMAND) bash
50+
4451
.PHONY:clean
4552
clean: ## purge build time artifacts
4653
rm -rf dist/ build/ coverage/ pypoetry/ pip/ **/__pycache__/ .pytest_cache/ .cache .coverage
4754

4855
.PHONY:changelog
49-
changelog: ## print the next version of the change log to stdout
56+
changelog: install ## print the next version of the change log to stdout
5057
$(POETRY_COMMAND) run semantic-release changelog --unreleased
5158

5259
.PHONY:install
53-
install: ## install development and build time dependencies
54-
$(POETRY_COMMAND) install --no-interaction -vvv
60+
install: build-image ## install development and build time dependencies
61+
$(POETRY_COMMAND) install --no-interaction
5562

5663
.PHONY:lint
57-
lint: ## run lint rules and print error report
64+
lint: install ## run lint rules and print error report
5865
$(POETRY_COMMAND) run task lint
5966

6067
.PHONY:lint-fix
61-
lint-fix:## attempt to auto fix linting error and report remaining errors
68+
lint-fix: install ## attempt to auto fix linting error and report remaining errors
6269
$(POETRY_COMMAND) run task lint:fix
6370

6471
.PHONY:package
65-
package: ## Generate a python sdist and wheel
72+
package: install ## Generate a python sdist and wheel
6673
$(POETRY_COMMAND) build
6774

6875
.PHONY:release
@@ -71,7 +78,6 @@ release: clean install fetch-tags ## run semantic release build and publish resu
7178

7279
.PHONY: fetch-tags
7380
fetch-tags: ## workaround for jenkins repo cloning behavior
74-
git config remote.origin.url "https://logdnabot:${GH_TOKEN}@github.com/logdna/python"
7581
git fetch origin --tags
7682

7783
.PHONY:release-dry
@@ -91,6 +97,5 @@ release-major: clean install ## run semantic release build an
9197
$(POETRY_COMMAND) run semantic-release publish --major
9298

9399
.PHONY:test
94-
test: ## run project test suite
100+
test: install ## run project test suite
95101
$(POETRY_COMMAND) run task test
96-

logdna/logdna.py

Lines changed: 69 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,13 @@ def try_request(self):
177177
self.close_flusher()
178178
self.exception_flag = True
179179

180-
def send_request(self, data):
180+
def send_request(self, data): # noqa: max-complexity: 13
181+
"""
182+
Send log data to LogDNA server
183+
Returns:
184+
True - discard flush buffer
185+
False - retry, keep flush buffer
186+
"""
181187
try:
182188
response = requests.post(url=self.url,
183189
json=data,
@@ -190,38 +196,84 @@ def send_request(self, data):
190196
'now': int(time.time() * 1000)
191197
},
192198
stream=True,
199+
allow_redirects=True,
193200
timeout=self.request_timeout,
194201
headers={'user-agent': self.user_agent})
195202

196-
response.raise_for_status()
197203
status_code = response.status_code
198-
if status_code in [401, 403]:
199-
self.internalLogger.debug(
200-
'Please provide a valid ingestion key.' +
201-
' Discarding flush buffer')
202-
return True
203-
204+
'''
205+
response code:
206+
1XX unexpected status
207+
200 expected status, OK
208+
2XX unexpected status
209+
301 302 303 unexpected status,
210+
per "allow_redirects=True"
211+
3XX unexpected status
212+
401, 403 expected client error,
213+
invalid ingestion key
214+
4XX unexpected client error
215+
500 502 503 507 expected server error, transient
216+
5XX unexpected server error
217+
handling:
218+
expected status discard flush buffer
219+
unexpected status log + discard flush buffer
220+
expected client error log + discard flush buffer
221+
unexpected client error log + discard flush buffer
222+
expected server error log + retry
223+
unexpected server error log + discard flush buffer
224+
'''
204225
if status_code == 200:
205-
return True
226+
return True # discard
206227

207-
if status_code in [400, 500, 504]:
208-
self.internalLogger.debug('The request failed %s. Retrying...',
209-
response.reason)
210-
return True
228+
if isinstance(response.reason, bytes):
229+
# We attempt to decode utf-8 first because some servers
230+
# choose to localize their reason strings. If the string
231+
# isn't utf-8, we fall back to iso-8859-1 for all other
232+
# encodings. (See PR #3538)
233+
try:
234+
reason = response.reason.decode('utf-8')
235+
except UnicodeDecodeError:
236+
reason = response.reason.decode('iso-8859-1')
211237
else:
238+
reason = response.reason
239+
240+
if 200 < status_code <= 399:
241+
self.internalLogger.debug('Unexpected response: %s. ' +
242+
'Discarding flush buffer',
243+
reason)
244+
return True # discard
245+
246+
if status_code in [401, 403]:
212247
self.internalLogger.debug(
213-
'The request failed: %s. Retrying...', response.reason)
248+
'Please provide a valid ingestion key. ' +
249+
'Discarding flush buffer')
250+
return True # discard
251+
252+
if 400 <= status_code <= 499:
253+
self.internalLogger.debug('Client Error: %s. ' +
254+
'Discarding flush buffer',
255+
reason)
256+
return True # discard
257+
258+
if status_code in [500, 502, 503, 507]:
259+
self.internalLogger.debug('Server Error: %s. Retrying...',
260+
reason)
261+
return False # retry
262+
263+
self.internalLogger.debug('The request failed: %s.' +
264+
'Discarding flush buffer',
265+
reason)
214266

215267
except requests.exceptions.Timeout as timeout:
216-
self.internalLogger.debug('Timeout error occurred %s. Retrying...',
268+
self.internalLogger.debug('Timeout Error: %s. Retrying...',
217269
timeout)
270+
return False # retry
218271

219272
except requests.exceptions.RequestException as exception:
220273
self.internalLogger.debug(
221274
'Error sending logs %s. Discarding flush buffer', exception)
222-
return True
223275

224-
return False
276+
return True # discard
225277

226278
def emit(self, record):
227279
msg = self.format(record)

0 commit comments

Comments
 (0)