Skip to content

Commit ed9fc3f

Browse files
ashbChris Fei
authored and
Chris Fei
committed
Validate task_log_reader on upgrade from <=1.9 (apache#3881)
We changed the default logging config and config from 1.9 to 1.10, but anyone who upgrades and has an existing airflow.cfg won't know they need to change this value - instead they will get nothing displayed in the UI (ajax request fails) and see "'NoneType' object has no attribute 'read'" in the error log. This validates that config section at start up, and seamlessly upgrades the old previous value.
1 parent cdf43ea commit ed9fc3f

File tree

2 files changed

+68
-6
lines changed

2 files changed

+68
-6
lines changed

airflow/logging_config.py

+33
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
# under the License.
1919
#
2020
import logging
21+
import warnings
2122
from logging.config import dictConfig
2223

2324
from airflow import configuration as conf
@@ -70,4 +71,36 @@ def configure_logging():
7071
# otherwise Airflow would silently fall back on the default config
7172
raise e
7273

74+
validate_logging_config(logging_config)
75+
7376
return logging_config
77+
78+
79+
def validate_logging_config(logging_config):
80+
# Now lets validate the other logging-related settings
81+
task_log_reader = conf.get('core', 'task_log_reader')
82+
83+
logger = logging.getLogger('airflow.task')
84+
85+
def _get_handler(name):
86+
return next((h for h in logger.handlers if h.name == name), None)
87+
88+
if _get_handler(task_log_reader) is None:
89+
# Check for pre 1.10 setting that might be in deployed airflow.cfg files
90+
if task_log_reader == "file.task" and _get_handler("task"):
91+
warnings.warn(
92+
"task_log_reader setting in [core] has a deprecated value of "
93+
"{!r}, but no handler with this name was found. Please update "
94+
"your config to use {!r}. Running config has been adjusted to "
95+
"match".format(
96+
task_log_reader,
97+
"task",
98+
),
99+
DeprecationWarning,
100+
)
101+
conf.set('core', 'task_log_reader', 'task')
102+
else:
103+
raise AirflowConfigException(
104+
"Configured task_log_reader {!r} was not a handler of the 'airflow.task' "
105+
"logger.".format(task_log_reader)
106+
)

tests/test_logging_config.py

+35-6
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,22 @@
1717
# specific language governing permissions and limitations
1818
# under the License.
1919
import os
20-
import shutil
20+
import six
2121
import sys
2222
import tempfile
23-
import unittest
2423
from mock import patch, mock
2524

2625
from airflow import configuration as conf
2726
from airflow.configuration import mkdir_p
2827
from airflow.exceptions import AirflowConfigException
2928

29+
30+
if six.PY2:
31+
# Need `assertWarns` back-ported from unittest2
32+
import unittest2 as unittest
33+
else:
34+
import unittest
35+
3036
SETTINGS_FILE_VALID = """
3137
LOGGING_CONFIG = {
3238
'version': 1,
@@ -41,14 +47,24 @@
4147
'class': 'logging.StreamHandler',
4248
'formatter': 'airflow.task',
4349
'stream': 'ext://sys.stdout'
44-
}
50+
},
51+
'task': {
52+
'class': 'logging.StreamHandler',
53+
'formatter': 'airflow.task',
54+
'stream': 'ext://sys.stdout'
55+
},
4556
},
4657
'loggers': {
4758
'airflow': {
4859
'handlers': ['console'],
4960
'level': 'INFO',
5061
'propagate': False
51-
}
62+
},
63+
'airflow.task': {
64+
'handlers': ['task'],
65+
'level': 'INFO',
66+
'propagate': False,
67+
},
5268
}
5369
}
5470
"""
@@ -200,18 +216,21 @@ def test_loading_no_local_settings(self):
200216
# When the key is not available in the configuration
201217
def test_when_the_config_key_does_not_exists(self):
202218
from airflow import logging_config
219+
conf_get = conf.get
203220

204221
def side_effect(*args):
205222
if args[1] == 'logging_config_class':
206223
raise AirflowConfigException
207224
else:
208-
return "bla_bla_from_test"
225+
return conf_get(*args)
209226

210227
logging_config.conf.get = mock.Mock(side_effect=side_effect)
211228

212229
with patch.object(logging_config.log, 'debug') as mock_debug:
213230
logging_config.configure_logging()
214-
mock_debug.assert_any_call('Could not find key logging_config_class in config')
231+
mock_debug.assert_any_call(
232+
'Could not find key logging_config_class in config'
233+
)
215234

216235
# Just default
217236
def test_loading_local_settings_without_logging_config(self):
@@ -222,6 +241,16 @@ def test_loading_local_settings_without_logging_config(self):
222241
'Unable to load custom logging, using default config instead'
223242
)
224243

244+
def test_1_9_config(self):
245+
from airflow.logging_config import configure_logging
246+
conf.set('core', 'task_log_reader', 'file.task')
247+
try:
248+
with self.assertWarnsRegex(DeprecationWarning, r'file.task'):
249+
configure_logging()
250+
self.assertEqual(conf.get('core', 'task_log_reader'), 'task')
251+
finally:
252+
conf.remove_option('core', 'task_log_reader', remove_default=False)
253+
225254

226255
if __name__ == '__main__':
227256
unittest.main()

0 commit comments

Comments
 (0)