All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.okta.cli.commands.Logs Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2020-Present Okta, Inc.
 *
 * Licensed 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.
 */
package com.okta.cli.commands;

import com.okta.cli.console.ConsoleOutput;
import com.okta.commons.lang.Strings;
import com.okta.sdk.client.Client;
import com.okta.sdk.client.Clients;
import com.okta.sdk.impl.resource.AbstractCollectionResource;
import com.okta.sdk.resource.log.LogEvent;
import com.okta.sdk.resource.log.LogEventList;
import com.okta.sdk.resource.log.LogOutcome;
import com.okta.sdk.resource.log.LogSeverity;
import picocli.CommandLine;

import java.time.Instant;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Date;

import static java.lang.Thread.sleep;

@CommandLine.Command(name = "logs",
                     description = "Lists Okta log events",
                     hidden = true)
public class Logs extends BaseCommand {

    @CommandLine.Option(names = {"-f", "--follow"}, description = "Polls for new log events.")
    protected boolean follow;

    @Override
    public int runCommand() throws Exception {

        Client client = Clients.builder().build();
        ConsoleOutput output = getConsoleOutput();

        // At most 1 hour back
        Instant since = Instant.now().minus(1, ChronoUnit.HOURS);
        LogEventList logs = client.getLogs(new Date(since.toEpochMilli()), null, null, null, null);

        output.bold("Time                      Severity  Status     Message\n");
        logs.stream().forEach(log -> writeEvent(output, logsBaseUrl(logs), log));

        if (follow) {
            String pagingUrl = nextUrlPage(null, logs);

            while (true) {
                sleep(2000);
                //"published gt \"" + lastEvent + "\""
                LogEventList moreLogs = client.http().get(pagingUrl, LogEventList.class);
                moreLogs.stream()
                        .forEach(log -> writeEvent(output, logsBaseUrl(moreLogs), log));
                pagingUrl = nextUrlPage(pagingUrl, moreLogs);
            }
        }

        return 0;
    }

    private String logsBaseUrl(LogEventList logs) {
        String url = logs.getResourceHref();
        if (url.startsWith("/")) {
            url = nextUrlPage(null, logs);
        }
        return url.replaceFirst("/api/v1/logs.*", "/api/v1/logs");
    }

    private String nextUrlPage(String currentPage, LogEventList logs) {
        // TODO dependency on the SDK `impl` module, the SDK will automatically follow result until it
        // finds an empty page for log polling we want to retry the empty page (after a short delay)
        if (!(logs instanceof AbstractCollectionResource)) {
            throw new IllegalStateException("LogEventList must be an instance of AbstractCollectionResource to resolve.");
        }
        String pagingUrl = ((AbstractCollectionResource) logs).getString("nextPage");
        return pagingUrl != null
                ? pagingUrl
                : currentPage;
    }

    private void writeEvent(ConsoleOutput output, String logUrl, LogEvent log) {
        output.write(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'hh:mm:ss.SSSX").withZone(ZoneOffset.UTC).format(log.getPublished().toInstant()));
        output.write("  ");
        writeSeverity(output, log.getSeverity());
        output.write("      ");
        writeStatus(output, log.getOutcome());
        output.write("  ");
        output.write(trim(log.getDisplayMessage()));
        output.write("  ");
        output.write(logUrl + "?filter=uuid+eq+%22" + log.getUuid() + "%22");
        output.writeLine("");
    }

    private static void writeStatus(ConsoleOutput output, LogOutcome outcome) {

        String format = "%-9s";
        if (outcome == null) {
            output.write(String.format(format, ""));
        } else {
            String result = outcome.getResult();
            switch (result) {
                case "SKIPPED":
                    output.writeWarning(String.format(format, result));
                    break;
                case "FAILURE":
                case "DENY":
                    output.writeError(String.format(format, result));
                    break;
                default:
                    output.write(String.format(format, result));
            }
        }
    }

    private static void writeSeverity(ConsoleOutput output, LogSeverity severity) {
        switch (severity) {
            case WARN:
                output.writeWarning(severity);
                break;
            case ERROR:
                output.writeError(severity);
                break;
            default:
                output.write(severity);
        }
    }

    private static String trim(String input) {
        return input == null
                ? ""
                : Strings.trimWhitespace(input);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy