diff --git a/jupyterhub-static/data/static/css/pages/admin.css b/jupyterhub-static/data/static/css/pages/admin.css
index f43cc10829daae85453a185a8060a1b37eb3f19a..3eedb007b25b2ed8a8553655f74fe092faec8047 100755
--- a/jupyterhub-static/data/static/css/pages/admin.css
+++ b/jupyterhub-static/data/static/css/pages/admin.css
@@ -29,6 +29,12 @@ color: #225f8d;
.nav-pills .nav-link.active {
background-color: #004176;
}
+
+.custom-control-input:checked ~ .custom-control-label::before {
+ background-color: #004176;
+ border-color: #225f8d;
+}
+
/*
.table-striped > tbody > tr:nth-of-type(2n+1):hover {
color: #212529;
diff --git a/jupyterhub-static/data/static/js/admin.js b/jupyterhub-static/data/static/js/admin.js
index 2e8a366c49aaf9087abed3e608d271a4643fd41a..4702b22fbb7488be24ce98f86bd0e9055eedc137 100755
--- a/jupyterhub-static/data/static/js/admin.js
+++ b/jupyterhub-static/data/static/js/admin.js
@@ -10,52 +10,174 @@ require(["jquery", "bootstrap", "moment", "jhapi", "utils"], function (
) {
"use strict";
- // Set and post log levels
+ // Logging functionalities
+ // ["jhub", "backend", "tunneling", "userlabs-mgr", "jusuf-cloud"]
["jhub", "backend", "tunneling", "userlabs-mgr", "jusuf-cloud"].forEach(function (system) {
if (system == "jhub") {
- var api_url = "api/loglevel";
+ var logger_url = "api/logger";
} else {
- var api_url = "api/" + system + "/loglevel";
+ var logger_url = "api/" + system + "/logger";
}
$(document).ready(function () {
- // Set log levels
- $.get(api_url, function (loglevels) {
- // console.log(system, loglevels);
- $("#" + system + "-stream-select").val(loglevels["stream"])
- $("#" + system + "-file-select").val(loglevels["file"])
- $("#" + system + "-mail-select").val(loglevels["mail"])
- $("#" + system + "-syslog-select").val(loglevels["syslog"])
- });
+ // Set inputs according to values from backend
+ ["stream", "file", "mail", "syslog"].forEach(function (handler) {
+ $.get(logger_url + "/" + handler, function (log_info) {
+ // console.log(handler, log_info);
+ let enabled = $.parseJSON(log_info["enabled"]);
+ $("#" + system + "-" + handler + "-create").prop("disabled", enabled);
+ $("#" + system + "-" + handler + "-patch").prop("disabled", !enabled);
+ $("#" + system + "-" + handler + "-delete").prop("disabled", !enabled);
+
+ toggle_log_infos(system, handler, enabled);
+
+ $("#" + system + "-" + handler + "-loglevel").val(log_info["level"]);
+ $("#" + system + "-" + handler + "-formatter").val(log_info["formatter"]);
+ switch (handler) {
+ case "file":
+ $("#" + system + "-" + handler + "-logfile").val(log_info["logfile"]);
+ break;
+ case "mail":
+ $("#" + system + "-" + handler + "-receiver").val(log_info["receiver"]);
+ $("#" + system + "-" + handler + "-host").val(log_info["host"]);
+ $("#" + system + "-" + handler + "-from").val(log_info["from"]);
+ $("#" + system + "-" + handler + "-subject").val(log_info["subject"]);
+ break;
+ case "syslog":
+ $("#" + system + "-" + handler + "-host").val(log_info["host"]);
+ $("#" + system + "-" + handler + "-port").val(log_info["port"]);
+ $("#" + system + "-" + handler + "-protocol").val(log_info["protocol"]);
+ let enabled = $.parseJSON(log_info["memory_enabled"]);
+ $("#" + system + "-" + handler + "-memory").prop("checked", enabled);
+ $("#" + system + "-" + handler + "-memory-capacity").val(log_info["memory_capacity"]);
+ $("#" + system + "-" + handler + "-memory-flushlevel").val(log_info["memory_flushlevel"]);
+ break;
+ }
+ })
+ })
});
["stream", "file", "mail", "syslog"].forEach(function (handler) {
- $("#" + system + "-" + handler + "-post").click(function () {
- $(this).attr("disabled", true);
- let level = $("#" + system + "-" + handler + "-select").val();
- $.post(api_url + "/" + handler + "/" + level)
- .always(function (data) {
- if (data.status == 200) {
- $("#" + system + "-" + handler + "-msg").text("Successfully updated the loglevel to " + level);
- $("#" + system + "-" + handler + "-post").removeClass("btn-primary");
- $("#" + system + "-" + handler + "-post").addClass("btn-success");
-
+ var handler_url = logger_url + "/" + handler;
+ // POST
+ $("#" + system + "-" + handler + "-create").click(function () {
+ $(this).prop("disabled", true);
+ $(this).html('<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>')
+ let loglevel = $("#" + system + "-" + handler + "-loglevel").val();
+ let formatter = $("#" + system + "-" + handler + "-formatter").val();
+ let post_url = handler_url + "/" + loglevel + "/" + formatter;
+ switch (handler) {
+ case "file":
+ var filename = $("#" + system + "-" + handler + "-logfile").val();
+ filename = encodeURIComponent(encodeURIComponent(filename));
+ post_url += "/" + filename;
+ break;
+ case "mail":
+ var receiver = $("#" + system + "-" + handler + "-receiver").val();
+ var host = $("#" + system + "-" + handler + "-host").val();
+ var from = $("#" + system + "-" + handler + "-from").val();
+ var subject = $("#" + system + "-" + handler + "-subject").val();
+ post_url += "/" + receiver + "/" + host + "/" + from + "/" + subject;
+ break;
+ case "syslog":
+ var host = $("#" + system + "-" + handler + "-host").val();
+ var port = $("#" + system + "-" + handler + "-port").val();
+ var protocol = $("#" + system + "-" + handler + "-protocol").val();
+ var memory = $("#" + system + "-" + handler + "-memory").prop("checked");
+ var memory_capacity = $("#" + system + "-" + handler + "-memory-capacity").val();
+ var memory_flushlevel = $("#" + system + "-" + handler + "-memory-flushlevel").val();
+ post_url += "/" + host + "/" + port + "/" + protocol + "/" + memory + "/" + memory_capacity + "/" + memory_flushlevel;
+ break;
+ }
+ $.post(post_url).always(function (response) {
+ if (response.status == 200) {
+ $("#" + system + "-" + handler + "-alert").text("Successfully created a new " + handler + " handler");
+ reset_alert(system, handler);
+ $("#" + system + "-" + handler + "-alert").addClass("alert-success");
+ $("#" + system + "-" + handler + "-create").prop("disabled", true);
+ $("#" + system + "-" + handler + "-patch").prop("disabled", false);
+ $("#" + system + "-" + handler + "-delete").prop("disabled", false);
+ toggle_log_infos(system, handler, true);
+ } else {
+ set_error_alert(system, handler, response);
+ $("#" + system + "-" + handler + "-create").prop("disabled", false);
+ }
+ $("#" + system + "-" + handler + "-create").html("Create");
+ })
+ });
+ // PATCH
+ $("#" + system + "-" + handler + "-patch").click(function () {
+ $(this).prop("disabled", true);
+ $(this).html('<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>')
+ let loglevel = $("#" + system + "-" + handler + "-loglevel").val();
+ let patch_url = handler_url + "/" + loglevel;
+ $.ajax({
+ url: patch_url,
+ type: 'PATCH',
+ })
+ .always(function (response) {
+ if (response.status == 200) {
+ $("#" + system + "-" + handler + "-alert").text("Successfully updated the loglevel to " + loglevel);
+ reset_alert(system, handler);
+ $("#" + system + "-" + handler + "-alert").addClass("alert-success");
} else {
- $("#" + system + "-" + handler + "-msg").text("Error: " + data.status + " " + data.statusText);
- $("#" + system + "-" + handler + "-post").removeClass("btn-primary");
- $("#" + system + "-" + handler + "-post").addClass("btn-danger");
+ set_error_alert(system, handler, response);
}
- })
- })
-
- $("#" + system + "-" + handler + "-select").change(function () {
- $("#" + system + "-" + handler + "-post").attr("disabled", false);
- $("#" + system + "-" + handler + "-post").addClass("btn-primary");
- $("#" + system + "-" + handler + "-post").removeClass("btn-success");
- $("#" + system + "-" + handler + "-post").removeClass("btn-danger");
- $("#" + system + "-" + handler + "-msg").text("");
- })
+ $("#" + system + "-" + handler + "-patch").prop("disabled", false);
+ $("#" + system + "-" + handler + "-patch").html("Patch");
+ });
+ });
+ // DELETE
+ $("#" + system + "-" + handler + "-delete").click(function () {
+ $(this).prop("disabled", true);
+ $(this).html('<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>')
+ $.ajax({
+ url: handler_url,
+ type: 'DELETE',
+ })
+ .always(function (response) {
+ if (response.status == 200) {
+ $("#" + system + "-" + handler + "-alert").text("Successfully deleted " + handler + " handler");
+ reset_alert(system, handler);
+ $("#" + system + "-" + handler + "-alert").addClass("alert-success");
+ $("#" + system + "-" + handler + "-create").prop("disabled", false);
+ $("#" + system + "-" + handler + "-patch").prop("disabled", true);
+ $("#" + system + "-" + handler + "-delete").prop("disabled", true);
+ toggle_log_infos(system, handler, false);
+ } else {
+ set_error_alert(system, handler, response);
+ $("#" + system + "-" + handler + "-delete").prop("disabled", false);
+ }
+ $("#" + system + "-" + handler + "-delete").html("Delete");
+ });
+ });
})
+
+ function toggle_log_infos(system, handler, enabled) {
+ let children = $("#" + system + "-" + handler).children();
+ if (enabled) {
+ children.prop("disabled", true);
+ $("#" + system + "-" + handler + "-loglevel").prop("disabled", false);
+ } else {
+ children.prop("disabled", false);
+ }
+ }
+
+ function set_error_alert(system, handler, response) {
+ if (response.status == 599) {
+ $("#" + system + "-" + handler + "-alert").text("Send failure: Broken pipe. Please try again");
+ } else {
+ $("#" + system + "-" + handler + "-alert").text("Error: " + response.status + " " + response.statusText);
+ }
+ reset_alert(system, handler);
+ $("#" + system + "-" + handler + "-alert").addClass("alert-danger");
+ }
+
+ function reset_alert(system, handler) {
+ $("#" + system + "-" + handler + "-alert").removeClass("alert-secondary");
+ $("#" + system + "-" + handler + "-alert").removeClass("alert-success");
+ $("#" + system + "-" + handler + "-alert").removeClass("alert-danger");
+ }
})
// User Lab table code
diff --git a/jupyterhub/config/data/templates/jupyter-jsc-devel.fz-juelich.de/admin.html b/jupyterhub/config/data/templates/jupyter-jsc-devel.fz-juelich.de/admin.html
index 4469e2da1028a76a2c6d78569989d9a15b1ab457..16ec7f4894558509770abf2bbb7ea95c4cbd5f7e 100755
--- a/jupyterhub/config/data/templates/jupyter-jsc-devel.fz-juelich.de/admin.html
+++ b/jupyterhub/config/data/templates/jupyter-jsc-devel.fz-juelich.de/admin.html
@@ -34,24 +34,89 @@
</li>
</ul>
<div class="tab-content" id="table-content">
- <div id="logging" class="tab-pane fade show active py-4" role="tabpanel" aria-labelledby="logging-tab">
- {% macro loglevel_select(log, system) %}
- <div class="form-group">
- <label for="{{system}}-{{log|lower}}-select">{{ log }} LogLevel</label>
- <select class="form-control" id="{{system}}-{{log|lower}}-select">
- <option value="NOTSET">NotSet</option>
- <option value="TRACE">Trace</option>
- <option value="DEBUG">Debug</option>
- <option value="INFO">Info</option>
- <option value="WARNING">Warning</option>
- <option value="ERROR">Error</option>
- <option value="CRITICAL">Critical</option>
- </select>
+ <div id="logging" class="tab-pane fade show active py-4" role="tabpanel" aria-labelledby="logging-tab">
+
+ {% macro request_buttons(log, system) %}
+ <div class="mb-2">
+ <button id="{{system}}-{{log|lower}}-create" type="button" class="btn btn-rounded btn-success">Create</button>
+ <button id="{{system}}-{{log|lower}}-patch" type="button" class="btn btn-rounded btn-primary">Patch</button>
+ <button id="{{system}}-{{log|lower}}-delete" type="button" class="btn btn-rounded btn-danger">Delete</button>
+ <div id="{{system}}-{{log|lower}}-alert" class="alert alert-secondary mt-2" role="alert">Output area</div>
</div>
- <button id="{{system}}-{{log|lower}}-post" class="btn btn-rounded btn-primary">Submit</button>
- <small id="{{system}}-{{log|lower}}-msg"></small>
{% endmacro %}
+ {% macro select(log, system, id="loglevel", text="LogLevel") %}
+ <label for="{{system}}-{{log|lower}}-{{id}}">{{ text }}</label>
+ <select class="form-control mb-2" id="{{system}}-{{log|lower}}-{{id}}">
+ <option value="NOTSET">NotSet</option>
+ <option value="TRACE">Trace</option>
+ <option value="DEBUG">Debug</option>
+ <option value="INFO">Info</option>
+ <option value="WARNING">Warning</option>
+ <option value="ERROR">Error</option>
+ <option value="CRITICAL">Critical</option>
+ <option value="DEACTIVATE">Deactivate</option>
+ </select>
+ {% endmacro %}
+
+ {% macro formatter(log, system) %}
+ <label for="{{system}}-{{log|lower}}-formatter">Formatter</label>
+ <select class="form-control mb-2" id="{{system}}-{{log|lower}}-formatter">
+ <option value="json">JSON</option>
+ <option value="simple">Simple</option>
+ </select>
+ {% endmacro %}
+
+ {% macro input(log, system, id, text, type="text") %}
+ <label for="{{system}}-{{log|lower}}-{{id}}">{{ text }}</label>
+ <input type={{type}} class="form-control mb-2" id="{{system}}-{{log|lower}}-{{id}}">
+ {% endmacro %}
+
+ {% macro stream_logger(log, system) %}
+ {{ request_buttons(log, system) }}
+ {{ select(log, system) }}
+ {{ formatter(log, system) }}
+ {% endmacro %}
+
+ {% macro file_logger(log, system) %}
+ {{ request_buttons(log, system) }}
+ {{ select(log, system) }}
+ {{ formatter(log, system) }}
+ {{ input(log, system, "logfile", "Log File") }}
+ {% endmacro %}
+
+ {% macro mail_logger(log, system) %}
+ {{ request_buttons(log, system) }}
+ {{ select(log, system) }}
+ {{ formatter(log, system) }}
+ {{ input(log, system, "receiver", "Receiver (if multiple, ; separated)") }}
+ {{ input(log, system, "host", "Host") }}
+ {{ input(log, system, "from", "From") }}
+ {{ input(log, system, "subject", "Subject") }}
+ {% endmacro %}
+
+ {% macro syslog_logger(log, system) %}
+ {{ request_buttons(log, system) }}
+ {{ select(log, system) }}
+ {{ formatter(log, system) }}
+ {{ input(log, system, "host", "Host") }}
+ {{ input(log, system, "port", "Port", type="number") }}
+ <label for="{{system}}-{{log|lower}}-protocol">{{ log }} Protocol</label>
+ <select class="form-control mb-2" id="{{system}}-{{log|lower}}-protocol">
+ <option value="udp">UDP</option>
+ <option value="tcp">TCP</option>
+ </select>
+ <hr/>
+ <div class="custom-control custom-switch mb-2">
+ <input class="custom-control-input" type="checkbox" id="{{system}}-{{log|lower}}-memory">
+ <label class="custom-control-label" for="{{system}}-{{log|lower}}-memory">
+ Enable SysLog memory
+ </label>
+ </div>
+ {{ input(log, system, "memory-capacity", "Memory Capacity", type="number") }}
+ {{ select(log, system, "memory-flushlevel", "Memory FlushLevel") }}
+ {% endmacro %}
+
{% macro loglevel_interface(title, system) %}
<div class="card bg-light border-dark mb-4">
<div class="card-body">
@@ -69,16 +134,16 @@
<div class="col-8">
<div class="tab-content" id="nav-tabContent">
<div class="tab-pane fade show active" id="{{system}}-stream" role="tabpanel" aria-labelledby="{{system}}-stream-list">
- {{ loglevel_select("Stream", system) }}
+ {{ stream_logger("Stream", system) }}
</div>
<div class="tab-pane fade" id="{{system}}-file" role="tabpanel" aria-labelledby="{{system}}-file-list">
- {{ loglevel_select("File", system) }}
+ {{ file_logger("File", system) }}
</div>
<div class="tab-pane fade" id="{{system}}-mail" role="tabpanel" aria-labelledby="{{system}}-mail-list">
- {{ loglevel_select("Mail", system) }}
+ {{ mail_logger("Mail", system) }}
</div>
<div class="tab-pane fade" id="{{system}}-syslog" role="tabpanel" aria-labelledby="{{system}}-syslog-list">
- {{ loglevel_select("SysLog", system) }}
+ {{ syslog_logger("SysLog", system) }}
</div>
</div>
</div>
diff --git a/jupyterhub/config/data/templates/jupyter-jsc.fz-juelich.de/admin.html b/jupyterhub/config/data/templates/jupyter-jsc.fz-juelich.de/admin.html
index 05fa31b29d4c3ddae7032fe4bc23629129187bcd..31b438544e45dec478f4fd472bf3b76e53016727 100755
--- a/jupyterhub/config/data/templates/jupyter-jsc.fz-juelich.de/admin.html
+++ b/jupyterhub/config/data/templates/jupyter-jsc.fz-juelich.de/admin.html
@@ -34,24 +34,89 @@
</li>
</ul>
<div class="tab-content" id="table-content">
- <div id="logging" class="tab-pane fade show active py-4" role="tabpanel" aria-labelledby="logging-tab">
- {% macro loglevel_select(log, system) %}
- <div class="form-group">
- <label for="{{system}}-{{log|lower}}-select">{{ log }} LogLevel</label>
- <select class="form-control" id="{{system}}-{{log|lower}}-select">
- <option value="NOTSET">NotSet</option>
- <option value="TRACE">Trace</option>
- <option value="DEBUG">Debug</option>
- <option value="INFO">Info</option>
- <option value="WARNING">Warning</option>
- <option value="ERROR">Error</option>
- <option value="CRITICAL">Critical</option>
- </select>
+ <div id="logging" class="tab-pane fade show active py-4" role="tabpanel" aria-labelledby="logging-tab">
+
+ {% macro request_buttons(log, system) %}
+ <div class="mb-2">
+ <button id="{{system}}-{{log|lower}}-create" type="button" class="btn btn-rounded btn-success">Create</button>
+ <button id="{{system}}-{{log|lower}}-patch" type="button" class="btn btn-rounded btn-primary">Patch</button>
+ <button id="{{system}}-{{log|lower}}-delete" type="button" class="btn btn-rounded btn-danger">Delete</button>
+ <div id="{{system}}-{{log|lower}}-alert" class="alert alert-secondary mt-2" role="alert">Output area</div>
</div>
- <button id="{{system}}-{{log|lower}}-post" class="btn btn-rounded btn-primary">Submit</button>
- <small id="{{system}}-{{log|lower}}-msg"></small>
{% endmacro %}
+ {% macro select(log, system, id="loglevel", text="LogLevel") %}
+ <label for="{{system}}-{{log|lower}}-{{id}}">{{ text }}</label>
+ <select class="form-control mb-2" id="{{system}}-{{log|lower}}-{{id}}">
+ <option value="NOTSET">NotSet</option>
+ <option value="TRACE">Trace</option>
+ <option value="DEBUG">Debug</option>
+ <option value="INFO">Info</option>
+ <option value="WARNING">Warning</option>
+ <option value="ERROR">Error</option>
+ <option value="CRITICAL">Critical</option>
+ <option value="DEACTIVATE">Deactivate</option>
+ </select>
+ {% endmacro %}
+
+ {% macro formatter(log, system) %}
+ <label for="{{system}}-{{log|lower}}-formatter">Formatter</label>
+ <select class="form-control mb-2" id="{{system}}-{{log|lower}}-formatter">
+ <option value="json">JSON</option>
+ <option value="simple">Simple</option>
+ </select>
+ {% endmacro %}
+
+ {% macro input(log, system, id, text, type="text") %}
+ <label for="{{system}}-{{log|lower}}-{{id}}">{{ text }}</label>
+ <input type={{type}} class="form-control mb-2" id="{{system}}-{{log|lower}}-{{id}}">
+ {% endmacro %}
+
+ {% macro stream_logger(log, system) %}
+ {{ request_buttons(log, system) }}
+ {{ select(log, system) }}
+ {{ formatter(log, system) }}
+ {% endmacro %}
+
+ {% macro file_logger(log, system) %}
+ {{ request_buttons(log, system) }}
+ {{ select(log, system) }}
+ {{ formatter(log, system) }}
+ {{ input(log, system, "logfile", "Log File") }}
+ {% endmacro %}
+
+ {% macro mail_logger(log, system) %}
+ {{ request_buttons(log, system) }}
+ {{ select(log, system) }}
+ {{ formatter(log, system) }}
+ {{ input(log, system, "receiver", "Receiver (if multiple, ; separated)") }}
+ {{ input(log, system, "host", "Host") }}
+ {{ input(log, system, "from", "From") }}
+ {{ input(log, system, "subject", "Subject") }}
+ {% endmacro %}
+
+ {% macro syslog_logger(log, system) %}
+ {{ request_buttons(log, system) }}
+ {{ select(log, system) }}
+ {{ formatter(log, system) }}
+ {{ input(log, system, "host", "Host") }}
+ {{ input(log, system, "port", "Port", type="number") }}
+ <label for="{{system}}-{{log|lower}}-protocol">{{ log }} Protocol</label>
+ <select class="form-control mb-2" id="{{system}}-{{log|lower}}-protocol">
+ <option value="udp">UDP</option>
+ <option value="tcp">TCP</option>
+ </select>
+ <hr/>
+ <div class="custom-control custom-switch mb-2">
+ <input class="custom-control-input" type="checkbox" id="{{system}}-{{log|lower}}-memory">
+ <label class="custom-control-label" for="{{system}}-{{log|lower}}-memory">
+ Enable SysLog memory
+ </label>
+ </div>
+ {{ input(log, system, "memory-capacity", "Memory Capacity", type="number") }}
+ {{ select(log, system, "memory-flushlevel", "Memory FlushLevel") }}
+ {% endmacro %}
+
{% macro loglevel_interface(title, system) %}
<div class="card bg-light border-dark mb-4">
<div class="card-body">
@@ -69,16 +134,16 @@
<div class="col-8">
<div class="tab-content" id="nav-tabContent">
<div class="tab-pane fade show active" id="{{system}}-stream" role="tabpanel" aria-labelledby="{{system}}-stream-list">
- {{ loglevel_select("Stream", system) }}
+ {{ stream_logger("Stream", system) }}
</div>
<div class="tab-pane fade" id="{{system}}-file" role="tabpanel" aria-labelledby="{{system}}-file-list">
- {{ loglevel_select("File", system) }}
+ {{ file_logger("File", system) }}
</div>
<div class="tab-pane fade" id="{{system}}-mail" role="tabpanel" aria-labelledby="{{system}}-mail-list">
- {{ loglevel_select("Mail", system) }}
+ {{ mail_logger("Mail", system) }}
</div>
<div class="tab-pane fade" id="{{system}}-syslog" role="tabpanel" aria-labelledby="{{system}}-syslog-list">
- {{ loglevel_select("SysLog", system) }}
+ {{ syslog_logger("SysLog", system) }}
</div>
</div>
</div>