public synchronized List<String> setLevel(String namespace, Level level) {
        Objects.requireNonNull(namespace, "Logging namespace may not be null");
        Objects.requireNonNull(level, "Level may not be null");

        log.info("Setting level of namespace {} and children to {}", namespace, level);
        List<org.apache.log4j.Logger> childLoggers = loggers(namespace);

        List<String> result = new ArrayList<>();
        for (org.apache.log4j.Logger logger: childLoggers) {
            setLevel(logger, level);
            result.add(logger.getName());
        }
        Collections.sort(result);

        return result;
    }
@Test
    public void testSetLevel() {
        Logger root = logger("root");
        root.setLevel(Level.ERROR);

        Logger x = logger("a.b.c.p.X");
        Logger y = logger("a.b.c.p.Y");
        Logger z = logger("a.b.c.p.Z");
        Logger w = logger("a.b.c.s.W");
        x.setLevel(Level.INFO);
        y.setLevel(Level.INFO);
        z.setLevel(Level.INFO);
        w.setLevel(Level.INFO);

        // We don't explicitly register a logger for a.b.c.p, so it won't appear in the list of current loggers;
        // one should be created by the Loggers instance when we set the level
        TestLoggers loggers = new TestLoggers(root, x, y, z, w);

        List<String> modified = loggers.setLevel("a.b.c.p", Level.DEBUG);
        assertEquals(Arrays.asList("a.b.c.p", "a.b.c.p.X", "a.b.c.p.Y", "a.b.c.p.Z"), modified);
        assertEquals(Level.DEBUG.toString(), loggers.level("a.b.c.p").level());
        assertEquals(Level.DEBUG, x.getLevel());
        assertEquals(Level.DEBUG, y.getLevel());
        assertEquals(Level.DEBUG, z.getLevel());

        LoggerLevel expectedLevel = new LoggerLevel(Level.DEBUG.toString(), INITIAL_TIME);
        LoggerLevel actualLevel = loggers.level("a.b.c.p");
        assertEquals(expectedLevel, actualLevel);

        // Sleep a little and adjust the level of a leaf logger
        time.sleep(10);
        loggers.setLevel("a.b.c.p.X", Level.ERROR);
        expectedLevel = new LoggerLevel(Level.ERROR.toString(), INITIAL_TIME + 10);
        actualLevel = loggers.level("a.b.c.p.X");
        assertEquals(expectedLevel, actualLevel);

        // Make sure that the direct parent logger and a sibling logger remain unaffected
        expectedLevel = new LoggerLevel(Level.DEBUG.toString(), INITIAL_TIME);
        actualLevel = loggers.level("a.b.c.p");
        assertEquals(expectedLevel, actualLevel);

        expectedLevel = new LoggerLevel(Level.DEBUG.toString(), INITIAL_TIME);
        actualLevel = loggers.level("a.b.c.p.Y");
        assertEquals(expectedLevel, actualLevel);

        // Set the same level again, and verify that the last modified time hasn't been altered
        time.sleep(10);
        loggers.setLevel("a.b.c.p.X", Level.ERROR);
        expectedLevel = new LoggerLevel(Level.ERROR.toString(), INITIAL_TIME + 10);
        actualLevel = loggers.level("a.b.c.p.X");
        assertEquals(expectedLevel, actualLevel);
    }