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";

Reply via email to