001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.rest.server.management;
018
019import java.util.*;
020
021import org.apache.juneau.rest.server.*;
022
023/**
024 * Shared worker for the {@code /loggers} management endpoint:  reads and sets logger levels at runtime by
025 * delegating to the {@link LogBackend} resolved from the host context.
026 *
027 * <p>
028 * Both the {@link LoggersMixin mixin} and {@link LoggersResource resource} flavors delegate here, so the
029 * two forms cannot drift &mdash; the same pattern the health package uses with its aggregator.
030 *
031 * <h5 class='section'>Backend</h5>
032 * <p>
033 * The driven backend defaults to {@link JulLogBackend java.util.logging}.  A consumer drives a different backend
034 * (e.g. Logback / Log4j2 via {@code juneau-rest-server-management-logging}) by <i>explicitly</i> declaring it on a
035 * {@link LoggersSettings} bean via {@link LoggersSettings.Builder#backend(LogBackend)} &mdash; the endpoint never
036 * auto-detects.  The response shape (logger name &rarr; configured level, empty string = inherited) is identical
037 * across backends.
038 *
039 * <h5 class='section'>See Also:</h5><ul>
040 *    <li class='jc'>{@link LogBackend}
041 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/ManagementSurface">Management Surface (Actuator-style endpoints)</a>
042 * </ul>
043 *
044 * @since 10.0.0
045 */
046public class LoggersManager {
047
048   /**
049    * Returns a snapshot of all known loggers and their configured levels, for the backend resolved from the
050    * supplied context.
051    *
052    * @param context The REST context whose bean store supplies the {@link LoggersSettings} / {@link LogBackend}.
053    *    May be <jk>null</jk> (uses the JUL default).
054    * @return A sorted map of logger name &rarr; configured level name (empty string = inherited).  Never <jk>null</jk>.
055    */
056   public Map<String,String> getLevels(RestContext context) {
057      return resolveSettings(context).getBackend().getLevels();
058   }
059
060   /**
061    * Returns the configured level of a single logger, for the backend resolved from the supplied context.
062    *
063    * @param context The REST context whose bean store supplies the backend.  May be <jk>null</jk>.
064    * @param name The logger name ({@code "ROOT"} or empty for the root logger).
065    * @return The configured level name, the empty string if the level is inherited, or <jk>null</jk> if no
066    *    such logger is currently registered.
067    */
068   public String getLevel(RestContext context, String name) {
069      return resolveSettings(context).getBackend().getLevel(name);
070   }
071
072   /**
073    * Sets (or clears) the level of a single logger at runtime (process-lifetime-only), for the backend resolved
074    * from the supplied context.
075    *
076    * @param context The REST context whose bean store supplies the backend.  May be <jk>null</jk>.
077    * @param name The logger name ({@code "ROOT"} or empty for the root logger).
078    * @param level The backend-native level name (e.g. {@code "FINE"}/{@code "INFO"} for JUL,
079    *    {@code "DEBUG"}/{@code "INFO"} for Logback/Log4j2), or <jk>null</jk>/blank to inherit.
080    * @throws IllegalArgumentException If {@code level} is non-blank but not a valid level name for the backend.
081    */
082   public void setLevel(RestContext context, String name, String level) {
083      resolveSettings(context).getBackend().setLevel(name, level);
084   }
085
086   /**
087    * Resolves the {@link LoggersSettings} from the host context's bean store, falling back to the
088    * read-only (JUL-backed) default.
089    *
090    * @param context The REST context whose bean store is searched.  May be <jk>null</jk>.
091    * @return The registered settings, or {@link LoggersSettings#DEFAULT} when none is registered.
092    */
093   @SuppressWarnings({
094      "resource" // The bean store is owned by the RestContext; this adapter only borrows beans and must not close it.
095   })
096   public LoggersSettings resolveSettings(RestContext context) {
097      if (context == null)
098         return LoggersSettings.DEFAULT;
099      return context.getBeanStore().getBean(LoggersSettings.class).orElse(LoggersSettings.DEFAULT);
100   }
101}