diff --git a/doc/admin-guide/logging/formatting.en.rst b/doc/admin-guide/logging/formatting.en.rst index bbb31501dc4..2d5ab388f4f 100644 --- a/doc/admin-guide/logging/formatting.en.rst +++ b/doc/admin-guide/logging/formatting.en.rst @@ -320,6 +320,7 @@ Identifiers .. _crid: .. _cruuid: .. _puuid: +.. _rcfln: Logging fields used to obtain various unique identifiers for transactions or objects. @@ -333,6 +334,10 @@ cruuid Client Request UUID of the current client request; generated by concatenating the puuid_ and crid_ field values. puuid Proxy Server UUID for the currently running :program:`traffic_server` process. Regenerated on every |TS| startup. +rcfln Proxy Server If the client request URL was remapped using a rule from + URL remapping configuration file (specified by + :ts:cv:`proxy.config.url_remap.filename`), the line number of + the rule in the file. Otherwise, the value is zero. ====== ============== ========================================================= .. _admin-logging-fields-lengths: diff --git a/proxy/http/remap/RemapConfig.cc b/proxy/http/remap/RemapConfig.cc index 1f889df14b2..39eb5b89600 100644 --- a/proxy/http/remap/RemapConfig.cc +++ b/proxy/http/remap/RemapConfig.cc @@ -1161,7 +1161,7 @@ remap_parse_config_bti(const char *path, BUILD_TABLE_INFO *bti) goto MAP_ERROR; } - new_mapping = new url_mapping(); + new_mapping = new url_mapping(cln + 1); // apply filter rules if we have to if ((errStr = process_filter_opt(new_mapping, bti, errStrBuf, sizeof(errStrBuf))) != nullptr) { @@ -1361,7 +1361,7 @@ remap_parse_config_bti(const char *path, BUILD_TABLE_INFO *bti) url_mapping *u_mapping; ats_ip_ntop(ai_spot->ai_addr, ipb, sizeof ipb); - u_mapping = new url_mapping; + u_mapping = new url_mapping(cln + 1); u_mapping->fromURL.create(nullptr); u_mapping->fromURL.copy(&new_mapping->fromURL); u_mapping->fromURL.host_set(ipb, strlen(ipb)); diff --git a/proxy/http/remap/UrlMapping.cc b/proxy/http/remap/UrlMapping.cc index e83d1c85fe1..987c473e6d7 100644 --- a/proxy/http/remap/UrlMapping.cc +++ b/proxy/http/remap/UrlMapping.cc @@ -28,7 +28,7 @@ /** * **/ -url_mapping::url_mapping() +url_mapping::url_mapping(int config_file_line_num) : _config_file_line_num(config_file_line_num) { memset(_plugin_list, 0, sizeof(_plugin_list)); memset(_instance_data, 0, sizeof(_instance_data)); diff --git a/proxy/http/remap/UrlMapping.h b/proxy/http/remap/UrlMapping.h index 89d4258fccf..f9f33befb09 100644 --- a/proxy/http/remap/UrlMapping.h +++ b/proxy/http/remap/UrlMapping.h @@ -79,7 +79,10 @@ class redirect_tag_str class url_mapping { public: - url_mapping(); + // Constructor parameter is the line number of the remapping from the configured url_remap file. The value should be zero if + // the remapping was not configured in this file. + // + url_mapping(int config_file_line_num); ~url_mapping(); bool add_plugin(remap_plugin_info *i, void *ih); @@ -122,11 +125,17 @@ class url_mapping { _rank = rank; }; + int + config_file_line_num() const + { + return _config_file_line_num; + } private: remap_plugin_info *_plugin_list[MAX_REMAP_PLUGIN_CHAIN]; void *_instance_data[MAX_REMAP_PLUGIN_CHAIN]; int _rank = 0; + int _config_file_line_num; }; /** diff --git a/proxy/http/remap/UrlRewrite.cc b/proxy/http/remap/UrlRewrite.cc index ef35a901861..6f46d467eed 100644 --- a/proxy/http/remap/UrlRewrite.cc +++ b/proxy/http/remap/UrlRewrite.cc @@ -144,7 +144,7 @@ UrlRewrite::SetupBackdoorMapping() const char from_url[] = "/ink/rh"; const char to_url[] = "http://{backdoor}/ink/rh"; - url_mapping *mapping = new url_mapping; + url_mapping *mapping = new url_mapping(0); mapping->fromURL.create(nullptr); mapping->fromURL.parse(from_url, sizeof(from_url) - 1); diff --git a/proxy/logging/Log.cc b/proxy/logging/Log.cc index 0a2fe4d0a27..528f9103212 100644 --- a/proxy/logging/Log.cc +++ b/proxy/logging/Log.cc @@ -484,6 +484,11 @@ Log::init_fields() global_field_list.add(field, false); ink_hash_table_insert(field_symbol_hash, "puuid", field); + field = new LogField("remap_config_file_line_number", "rcfln", LogField::sINT, &LogAccess::marshal_url_remap_config_line_num, + &LogAccess::unmarshal_int_to_str); + global_field_list.add(field, false); + ink_hash_table_insert(field_symbol_hash, "rcfln", field); + // TS-4765: This alias is deprecated to be removed in 8.0. field = new LogField("client_req_body_len", "cqbl", LogField::sINT, &LogAccess::marshal_client_req_content_len, &LogAccess::unmarshal_int_to_str); diff --git a/proxy/logging/LogAccess.cc b/proxy/logging/LogAccess.cc index 916db70b30a..d652246f34c 100644 --- a/proxy/logging/LogAccess.cc +++ b/proxy/logging/LogAccess.cc @@ -498,6 +498,11 @@ LOG_ACCESS_DEFAULT_FIELD(marshal_client_http_connection_id, DEFAULT_INT_FIELD) LOG_ACCESS_DEFAULT_FIELD(marshal_client_http_transaction_id, DEFAULT_INT_FIELD) +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +LOG_ACCESS_DEFAULT_FIELD(marshal_url_remap_config_line_num, DEFAULT_INT_FIELD) + /*------------------------------------------------------------------------- -------------------------------------------------------------------------*/ diff --git a/proxy/logging/LogAccess.h b/proxy/logging/LogAccess.h index 47d368bcf9c..75bee95d656 100644 --- a/proxy/logging/LogAccess.h +++ b/proxy/logging/LogAccess.h @@ -277,6 +277,7 @@ class LogAccess inkcoreapi virtual int marshal_process_uuid(char *); // STR inkcoreapi virtual int marshal_client_http_connection_id(char *); // INT inkcoreapi virtual int marshal_client_http_transaction_id(char *); // INT + inkcoreapi virtual int marshal_url_remap_config_line_num(char *); // INT // These two are special, in that they are shared for all log types / implementations inkcoreapi int marshal_entry_type(char *); // INT diff --git a/proxy/logging/LogAccessHttp.cc b/proxy/logging/LogAccessHttp.cc index 93e15ce9bc2..4384546490a 100644 --- a/proxy/logging/LogAccessHttp.cc +++ b/proxy/logging/LogAccessHttp.cc @@ -1505,6 +1505,25 @@ LogAccessHttp::marshal_client_http_transaction_id(char *buf) return INK_MIN_ALIGN; } +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +int +LogAccessHttp::marshal_url_remap_config_line_num(char *buf) +{ + if (buf) { + int64_t line_num = 0; + if (m_http_sm) { + auto m = m_http_sm->t_state.url_map.getMapping(); + if (m) { + line_num = m->config_file_line_num(); + } + } + marshal_int(buf, line_num); + } + return INK_MIN_ALIGN; +} + /*------------------------------------------------------------------------- -------------------------------------------------------------------------*/ diff --git a/proxy/logging/LogAccessHttp.h b/proxy/logging/LogAccessHttp.h index 0c20ef25a6f..a4f9655b97c 100644 --- a/proxy/logging/LogAccessHttp.h +++ b/proxy/logging/LogAccessHttp.h @@ -155,6 +155,7 @@ class LogAccessHttp : public LogAccess int marshal_cache_lookup_url_canon(char *) override; // STR int marshal_client_http_connection_id(char *) override; // INT int marshal_client_http_transaction_id(char *) override; // INT + int marshal_url_remap_config_line_num(char *) override; // INT // // named fields from within a http header diff --git a/tests/gold_tests/logging/gold/test_rcfln.gold b/tests/gold_tests/logging/gold/test_rcfln.gold new file mode 100644 index 00000000000..56aa836c979 --- /dev/null +++ b/tests/gold_tests/logging/gold/test_rcfln.gold @@ -0,0 +1,5 @@ +1 +6 +1 +0 +4 diff --git a/tests/gold_tests/logging/remap_line_num.test.py b/tests/gold_tests/logging/remap_line_num.test.py new file mode 100644 index 00000000000..fe8ecbb1b93 --- /dev/null +++ b/tests/gold_tests/logging/remap_line_num.test.py @@ -0,0 +1,107 @@ +''' +''' +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import subprocess + +Test.Summary = ''' +Test new log field giving line number in config file of rule used to remap URL. +''' + +Test.SkipUnless( + Condition.HasProgram("curl", "Curl need to be installed on system for this test to work") +) +Test.ContinueOnFail = True + +ts = Test.MakeATSProcess("ts", select_ports=False) + +ts.Disk.records_config.update({ + # 'proxy.config.diags.debug.enabled': 1, + 'proxy.config.http.server_ports': 'ipv4:{0}'.format(ts.Variables.port) +}) + +ts.Disk.remap_config.AddLine( + 'map http://127.0.0.1:{0} http://httpbin.org/ip'.format(ts.Variables.port) +) + +ts.Disk.remap_config.AddLine('') +ts.Disk.remap_config.AddLine('') + +ts.Disk.remap_config.AddLine( + 'map http://127.0.0.3:{0} http://httpbin.org/ip'.format(ts.Variables.port) +) + +ts.Disk.remap_config.AddLine('') + +ts.Disk.remap_config.AddLine( + 'map http://127.0.0.2:{0} http://httpbin.org/ip'.format(ts.Variables.port) +) + +ts.Disk.logging_config.AddLines( + '''custom = format { + Format = "%" +} + +log.ascii { + Format = custom, + Filename = 'test_rcfln' +}'''.split("\n") +) + +Test.Disk.File(os.path.join(ts.Variables.LOGDIR, 'test_rcfln.log'), + exists=True, content='gold/test_rcfln.gold') + +# Ask the OS if the port is ready for connect() +# +def CheckPort(Port): + return lambda: 0 == subprocess.call('netstat --listen --tcp -n | grep -q :{}'.format(Port), shell=True) + +tr = Test.AddTestRun() +# Delay on readiness of port +tr.Processes.Default.StartBefore(Test.Processes.ts, ready=CheckPort(ts.Variables.port)) +# +tr.Processes.Default.Command = 'curl "http://127.0.0.1:{0}" --verbose'.format( + ts.Variables.port) +tr.Processes.Default.ReturnCode = 0 + +tr = Test.AddTestRun() +tr.Processes.Default.Command = 'curl "http://127.0.0.2:{0}" --verbose'.format( + ts.Variables.port) +tr.Processes.Default.ReturnCode = 0 + +tr = Test.AddTestRun() +tr.Processes.Default.Command = 'curl "http://127.0.0.1:{0}" --verbose'.format( + ts.Variables.port) +tr.Processes.Default.ReturnCode = 0 + +# Unremapped URL +tr = Test.AddTestRun() +tr.Processes.Default.Command = 'curl "http://127.0.0.4:{0}" --verbose'.format( + ts.Variables.port) +tr.Processes.Default.ReturnCode = 0 + +tr = Test.AddTestRun() +tr.Processes.Default.Command = 'curl "http://127.0.0.3:{0}" --verbose'.format( + ts.Variables.port) +tr.Processes.Default.ReturnCode = 0 + +# Delay to give ATS time to generate log entries. +tr = Test.AddTestRun() +tr.Processes.Default.Command = 'echo WAIT' +tr.DelayStart = 10 +tr.Processes.Default.ReturnCode = 0