This is an automated email from the ASF dual-hosted git repository.
jscheffl pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new 42266e1a07 Add color formatting for ANSI chars in logs from task
executions (#37985)
42266e1a07 is described below
commit 42266e1a07f366150b427763e99fbde9b16effcf
Author: Jens Scheffler <[email protected]>
AuthorDate: Fri Mar 8 22:15:08 2024 +0100
Add color formatting for ANSI chars in logs from task executions (#37985)
* Add color formatting for ANSI chars in logs from task executions
* Fix ts tests, remove custom HTML escaping and urlifying with lib
* Fix URLifying v2 - is not working as expected with ansi_up
---
airflow/example_dags/example_bash_operator.py | 2 +-
airflow/www/jest.config.js | 1 +
airflow/www/package.json | 3 +--
.../js/dag/details/taskInstance/Logs/utils.ts | 25 +++++-----------------
airflow/www/static/js/ti_log.js | 8 ++++---
airflow/www/yarn.lock | 24 +++++----------------
6 files changed, 18 insertions(+), 45 deletions(-)
diff --git a/airflow/example_dags/example_bash_operator.py
b/airflow/example_dags/example_bash_operator.py
index 2988479e36..781a840894 100644
--- a/airflow/example_dags/example_bash_operator.py
+++ b/airflow/example_dags/example_bash_operator.py
@@ -42,7 +42,7 @@ with DAG(
# [START howto_operator_bash]
run_this = BashOperator(
task_id="run_after_loop",
- bash_command="echo 1",
+ bash_command="ls -alh --color=always / && echo
https://airflow.apache.org/ && echo 'some <code>html</code>'",
)
# [END howto_operator_bash]
diff --git a/airflow/www/jest.config.js b/airflow/www/jest.config.js
index 84e1ced6d1..333a061268 100644
--- a/airflow/www/jest.config.js
+++ b/airflow/www/jest.config.js
@@ -32,6 +32,7 @@ const config = {
transformIgnorePatterns: [
`node_modules/(?!${[
// specify modules that needs to be transformed for jest. (esm modules)
+ "ansi_up",
"axios",
"bail",
"ccount",
diff --git a/airflow/www/package.json b/airflow/www/package.json
index 1a6866e107..e6149c8bd1 100644
--- a/airflow/www/package.json
+++ b/airflow/www/package.json
@@ -55,7 +55,6 @@
"@types/react-dom": "^18.0.5",
"@types/react-syntax-highlighter": "^15.5.6",
"@types/react-table": "^7.7.12",
- "@types/sanitize-html": "^2.9.5",
"@typescript-eslint/eslint-plugin": "^5.13.0",
"@typescript-eslint/parser": "^5.0.0",
"babel-jest": "^27.3.1",
@@ -106,6 +105,7 @@
"@emotion/styled": "^11",
"@visx/group": "^2.10.0",
"@visx/shape": "^2.12.2",
+ "ansi_up": "^6.0.2",
"axios": "^1.6.0",
"bootstrap-3-typeahead": "^4.0.2",
"camelcase-keys": "^7.0.0",
@@ -141,7 +141,6 @@
"reactflow": "^11.7.4",
"redoc": "^2.0.0-rc.72",
"remark-gfm": "^3.0.1",
- "sanitize-html": "^2.12.1",
"swagger-ui-dist": "4.1.3",
"tsconfig-paths": "^3.14.2",
"type-fest": "^2.17.0",
diff --git a/airflow/www/static/js/dag/details/taskInstance/Logs/utils.ts
b/airflow/www/static/js/dag/details/taskInstance/Logs/utils.ts
index c3c4084044..44e8d4a46c 100644
--- a/airflow/www/static/js/dag/details/taskInstance/Logs/utils.ts
+++ b/airflow/www/static/js/dag/details/taskInstance/Logs/utils.ts
@@ -19,10 +19,9 @@
/* global moment */
+import { AnsiUp } from "ansi_up";
import { defaultFormatWithTZ } from "src/datetime_utils";
-import sanitizeHtml from "sanitize-html";
-
export enum LogLevel {
DEBUG = "DEBUG",
INFO = "INFO",
@@ -61,6 +60,7 @@ export const parseLogs = (
const parsedLines: Array<string> = [];
const fileSources: Set<string> = new Set();
+ const ansiUp = new AnsiUp();
lines.forEach((line) => {
let parsedLine = line;
@@ -99,29 +99,14 @@ export const parseLogs = (
line.includes(fileSourceFilter)
)
) {
- // sanitize the lines to remove any tags that may cause HTML injection
- const sanitizedLine = sanitizeHtml(parsedLine, {
- allowedTags: ["a"],
- allowedAttributes: {
- a: ["href", "target", "style"],
- },
- transformTags: {
- a: (tagName, attribs) => {
- attribs.style = "color: blue; text-decoration: underline;";
- return {
- tagName: "a",
- attribs,
- };
- },
- },
- });
+ // for lines with color convert to nice HTML
+ const coloredLine = ansiUp.ansi_to_html(parsedLine);
// for lines with links, transform to hyperlinks
- const lineWithHyperlinks = sanitizedLine.replace(
+ const lineWithHyperlinks = coloredLine.replace(
/((https?:\/\/|http:\/\/)[^\s]+)/g,
'<a href="$1" target="_blank" style="color: blue; text-decoration:
underline;">$1</a>'
);
-
parsedLines.push(lineWithHyperlinks);
}
});
diff --git a/airflow/www/static/js/ti_log.js b/airflow/www/static/js/ti_log.js
index 02f2aa1427..cbafeccbc3 100644
--- a/airflow/www/static/js/ti_log.js
+++ b/airflow/www/static/js/ti_log.js
@@ -18,7 +18,7 @@
*/
/* global document, window, $ */
-import { escapeHtml } from "./main";
+import { AnsiUp } from "ansi_up";
import { getMetaValue } from "./utils";
import { formatDateTime } from "./datetime_utils";
@@ -107,6 +107,8 @@ function autoTailingLog(tryNumber, metadata = null,
autoTailing = false) {
shouldScroll = true;
}
+ // Text coloring, detect urls and log timestamps
+ const ansiUp = new AnsiUp();
// Detect urls and log timestamps
const urlRegex =
/http(s)?:\/\/[\w.-]+(\.?:[\w.-]+)*([/?#][\w\-._~:/?#[\]@!$&'()*+,;=.%]+)?/g;
@@ -129,8 +131,8 @@ function autoTailingLog(tryNumber, metadata = null,
autoTailing = false) {
}
// The message may contain HTML, so either have to escape it or write
it as text.
- const escapedMessage = escapeHtml(item[1]);
- const linkifiedMessage = escapedMessage
+ const coloredMessage = ansiUp.ansi_to_html(item[1]);
+ const linkifiedMessage = coloredMessage
.replace(
urlRegex,
(url) =>
diff --git a/airflow/www/yarn.lock b/airflow/www/yarn.lock
index b7934895cc..ba8c8fc336 100644
--- a/airflow/www/yarn.lock
+++ b/airflow/www/yarn.lock
@@ -3473,13 +3473,6 @@
"@types/scheduler" "*"
csstype "^3.0.2"
-"@types/sanitize-html@^2.9.5":
- version "2.9.5"
- resolved
"https://registry.yarnpkg.com/@types/sanitize-html/-/sanitize-html-2.9.5.tgz#e8b2214c8afc7bb88d62f9c3bbbc5b4ecc80a25d"
- integrity
sha512-2Sr1vd8Dw+ypsg/oDDfZ57OMSG2Befs+l2CMyCC5bVSK3CpE7lTB2aNlbbWzazgVA+Qqfuholwom6x/mWd1qmw==
- dependencies:
- htmlparser2 "^8.0.0"
-
"@types/scheduler@*":
version "0.16.2"
resolved
"https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39"
@@ -3970,6 +3963,11 @@ ansi-styles@^5.0.0:
resolved
"https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b"
integrity
sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==
+ansi_up@^6.0.2:
+ version "6.0.2"
+ resolved
"https://registry.yarnpkg.com/ansi_up/-/ansi_up-6.0.2.tgz#083adb65be5b21ba283fd105d3102e64f3f0b092"
+ integrity
sha512-3G3vKvl1ilEp7J1u6BmULpMA0xVoW/f4Ekqhl8RTrJrhEBkonKn5k3bUc5Xt+qDayA6iDX0jyUh3AbZjB/l0tw==
+
anymatch@^3.0.0, anymatch@^3.0.3:
version "3.1.2"
resolved
"https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716"
@@ -10426,18 +10424,6 @@ safe-regex-test@^1.0.0:
resolved
"https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity
sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
-sanitize-html@^2.12.1:
- version "2.12.1"
- resolved
"https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-2.12.1.tgz#280a0f5c37305222921f6f9d605be1f6558914c7"
- integrity
sha512-Plh+JAn0UVDpBRP/xEjsk+xDCoOvMBwQUf/K+/cBAVuTbtX8bj2VB7S1sL1dssVpykqp0/KPSesHrqXtokVBpA==
- dependencies:
- deepmerge "^4.2.2"
- escape-string-regexp "^4.0.0"
- htmlparser2 "^8.0.0"
- is-plain-object "^5.0.0"
- parse-srcset "^1.0.2"
- postcss "^8.3.11"
-
sax@^1.2.4:
version "1.2.4"
resolved
"https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"