12 Replies Latest reply on Aug 23, 2017 5:41 PM by delphinus818

    Wildfly 10.0.0 Accessing CLI programmatically

    delphinus818

      What is the right way to access CLI programmatically using Wildfly 10.0.0?  I tried to use jboss-deployment-structure.xml to specify org.jboss.as.cli as a module and exclude all dependencies.  I got the following error:

       

      CliInitializationException : org.jboss.as.cli.CliInitializationException: Failed to load org.jboss.as.cli.impl.CommandContextFactoryImpl

      at org.jboss.as.cli.CommandContextFactory.getInstance(CommandContextFactory.java:43)

       

      If I tried to package jboss-as-cli as a dependency, then I also had to package staxmapper as a dependency, eventually it will lead to the following error using this approach:

       

      Exception when handling error trying to reset the response.: java.util.ServiceConfigurationError: org.jboss.as.cli.CommandHandlerProvider: Provider org.wildfly.extension.messaging.activemq.jms.cli.ConnectionFactoryHandlerProvider not a subtype

      at java.util.ServiceLoader.fail(ServiceLoader.java:239) [rt.jar:1.8.0_71]

      at java.util.ServiceLoader.access$300(ServiceLoader.java:185) [rt.jar:1.8.0_71]

      at java.util.ServiceLoader$LazyIterator.nextService(ServiceLoader.java:376) [rt.jar:1.8.0_71]

      at java.util.ServiceLoader$LazyIterator.next(ServiceLoader.java:404) [rt.jar:1.8.0_71]

      at java.util.ServiceLoader$1.next(ServiceLoader.java:480) [rt.jar:1.8.0_71]

      at org.jboss.as.cli.impl.CommandContextImpl.registerExtraHandlers(CommandContextImpl.java:591) [jboss-cli-client.jar:2.0.10.Final]

      at org.jboss.as.cli.impl.CommandContextImpl.initCommands(CommandContextImpl.java:584) [jboss-cli-client.jar:2.0.10.Final]

      at org.jboss.as.cli.impl.CommandContextImpl.<init>(CommandContextImpl.java:302) [jboss-cli-client.jar:2.0.10.Final]

      at org.jboss.as.cli.impl.CommandContextFactoryImpl.newCommandContext(CommandContextFactoryImpl.java:44) [jboss-cli-client.jar:2.0.10.Final]

       

      The code is something like this:

       

      //CLI API

      import org.jboss.as.cli.CliInitializationException;

      import org.jboss.as.cli.CommandContext; 

      import org.jboss.as.cli.CommandContextFactory;

      import org.jboss.as.cli.CommandLineException; 

      import org.jboss.as.cli.CommandFormatException;

      import org.jboss.as.controller.client.ModelControllerClient;

       

       

      // DMR API 

      import org.jboss.dmr.ModelNode;

       

      public class CLILoggingImpl implements LoggingConfiguration { 

          private static final Logger logger = Logger.getLogger(CLILoggingImpl.class);

          private static CommandContext ctx;

          private String failureDescription;

          private Handler handlerType = Handler.UNKNOWN;

          private ModelNode result;

          private Level logLevel = null;

          private String rotateSize = null;

          private String maxBackupIndex = null;

       

       

          public CLILoggingImpl() {

              try {

                  logger.debug("CLILogging Init...");

                  ctx = CommandContextFactory.getInstance().newCommandContext();

              }

              catch(CliInitializationException e) {

                  logger.debug("CliInitializationException ", e);

                  //throw new IllegalStateException("Failed to initialize CLI context", e);

              }

          }

         

         

          private LResult connectHandler(String request) {

              try {

                  ctx.connectController();

                  logger.debug("Running command ---- " + request); 

                  CommandResult res = runCommands(request);

                  ctx.disconnectController();

                  .......

       

              }

             

              catch (CommandLineException e) {

                  logger.error("Failed to connect, CommandLineException ", e);

                  this.failureDescription = e.getMessage();

                  return LResult.FAILED;

              }

          }

        • 1. Re: Wildfly 10.0.0 Accessing CLI programmatically
          jamezp

          I'e never tried using CLI within an application. Is there a reason you want to use CLI vs DMR and the controller client?

           

          --

          James R. Perkins

          • 2. Re: Wildfly 10.0.0 Accessing CLI programmatically
            delphinus818

            The user wants to change the log4j parameters (log level, max size, etc.) programmatically, without changing log4j config file manually.  We use  log4j configuration within the same config file as JBOSS (such as standalone-full.xml).  I have to access CLI from an application to issue CLI commands to change the log level, max size, backup index directly to JBOSS.  It works as a standalone executable (with jboss-cli-client.jar on the classpath), but when I deploy it as an ear file within JBOSS then I run into class loading problems, as mentioned above.  I don't know what is the right way to use jboss.as.cli as a dependency without clashing with JBOSS.  If I exclude the dependency by using jboss-deployment-structure.xml to exclude all dependencies I ran into the error as mentioned above, if I tried to package the dependencies into the ear file I also ran into error as mentioned above.

             

            I'm not sure which one to package if this is the right way.  I've tried the followings but don't know which is the right version for Wildfly 10.0.0.  Thanks a lot for your reply.

             

            <dependency>

              <groupId>org.jboss.as</groupId>

              <artifactId>jboss-as-cli</artifactId>

              <version>7.5.5.Final-redhat-3</version>

            </dependency>

            <dependency>

              <groupId>org.jboss</groupId>

              <artifactId>staxmapper</artifactId>

              <version>1.3.0.Final</version>

            </dependency>

            <dependency> 

              <groupId>org.wildfly.core</groupId> 

              <artifactId>wildfly-cli</artifactId> 

              <version>2.0.10.Final</version>

              </dependency> 

            • 3. Re: Wildfly 10.0.0 Accessing CLI programmatically
              jamezp

              I guess my point is you don't need to use CLI to make manage management changes. You could also use the ModelControllerClient and DMR to create management operations.

               

              import org.jboss.as.controller.client.ModelControllerClient;

              import org.jboss.as.controller.client.helpers.Operations;

              import org.jboss.dmr.ModelNode;

               

              public class Example {

                  public static void main(String[] args) throws Exception {

                      try (ModelControllerClient client = ModelControllerClient.Factory.create("localhost", 9990)) {

                          final ModelNode handlerAddress = Operations.createAddress("subsystem", "logging", "console-handler", "CONSOLE");

                          final ModelNode op = Operations.createWriteAttributeOperation(handlerAddress, "level", "DEBUG");

                          final ModelNode result = client.execute(op);

                          if (Operations.isSuccessfulOutcome(result)) {

                              // do something

                          } else {

                              throw new RuntimeException("Failed to execute operation: " + op + " " +

                                      Operations.getFailureDescription(result).asString());

                          }

                      }

                  }

              }

               

              I'm not really sure what you mean by log4j configuration though. WildFly doesn't use log4j internally, but that's somewhat irrelevant.

               

              One thing to consider is this will globally change the logging configuration, not just the logging configuration for the application.

               

              --

              James R. Perkins

              • 4. Re: Wildfly 10.0.0 Accessing CLI programmatically
                delphinus818

                I will try your suggestion.  Do I have to package all the dependencies into the ear file?  I will have to find the dependencies by "trial and error", deploying and add one by one to the list of dependencies.  Is there a way to find out which versions of the dependencies are compatible with Wildfly 10.0.0?

                 

                You're right, log4j is irrelevant to Wildfly (I'm also changing other services which use log4j), and we do want to change the configuration globally.  Thank you.

                • 5. Re: Wildfly 10.0.0 Accessing CLI programmatically
                  jamezp

                  You could probably package them in your EAR. I believe the modules are marked as private. You could just use the org.wildfly:wildfly-client-all dependency.

                   

                  --

                  James R. Perkins

                  • 6. Re: Wildfly 10.0.0 Accessing CLI programmatically
                    delphinus818

                    I implemented this change and it worked on a http server but not on a https server, do you know why?  On an HTTPS server, the max size and max backup index took effect but the log level would not work, even after I restart the App Server.

                     

                    I used CLI command to read the JBOSS config file, it read it correctly (DEBUG) but the log doesn’t show any DEBUG log.

                    • 7. Re: Wildfly 10.0.0 Accessing CLI programmatically
                      jamezp

                      That really shouldn't matter. That's just a connection protocol. If the management interface is also using HTTPS you'd need to use the remote+https protocol.

                       

                      --

                      James R. Perkins

                      • 8. Re: Wildfly 10.0.0 Accessing CLI programmatically
                        delphinus818

                        What is the right syntax for updating the log level in the root-logger?  The following works for reading:

                         

                        rootAddress = Operations.createAddress("subsystem", "logging", "root-logger");

                        op = Operations.createReadAttributeOperation(rootAddress, "level");

                         

                        But when I tried to do the same thing to write it gave me an error, the following doesn't work for writing:

                         

                        rootAddress = Operations.createAddress("subsystem", "logging", "root-logger");

                        ModelNode op = Operations.createWriteAttributeOperation(rootAddress, "level", "DEBUG");

                         

                        Also, if I have different levels set in handler and in root-logger, which one should be in effect and which one should be changed?

                         

                        <periodic-rotating-file-handler name="FILE" autoflush="true">

                                        <level name="INFO"/>

                                        <formatter>

                                            <pattern-formatter pattern="%d %-5p [%c] (%t) %s%E%n"/>

                                        </formatter>

                                        <file relative-to="jboss.server.log.dir" path="../../../log/bis.log"/>

                                        <suffix value=".yyyy-MM-dd"/>

                                        <append value="true"/>

                        </periodic-rotating-file-handler>

                         

                        <root-logger>

                                        <level name="DEBUG"/>

                                        <handlers>

                                            <handler name="CONSOLE"/>

                                            <handler name="FILE"/>

                                        </handlers>

                        </root-logger>

                         

                        Thanks a lot for your help.

                        • 9. Re: Wildfly 10.0.0 Accessing CLI programmatically
                          jamezp

                          The address is missing the address value of the root-logger resource. For the root-logger this is hard-coded as ROOT. So it should be rootAddress = Operations.createAddress("subsystem", "logging", "root-logger", "ROOT").

                           

                          The XML and the model don't always compare on a 1-1 relationship. Resources addresses are name/value pairs. With some operations you can use a wildcard (*), but not for updates only reads. Wildscribe is always a good resource to see the model. You could also just read a subsystem model to see the layout as well. Looking at it in CLI may help.

                          /subsystem=logging:read-children-resources(child-type=root-logger)
                          

                           

                          That results in something like:

                          {
                              "outcome" => "success",
                              "result" => {"ROOT" => {
                                  "filter" => undefined,
                                  "filter-spec" => undefined,
                                  "handlers" => [
                                      "CONSOLE",
                                      "FILE"
                                  ],
                                  "level" => "INFO"
                              }}
                          }
                          

                           

                          Here the "ROOT" is the name of the resource and the other attributes and resources defined.

                           

                          Don't forget with CLI you've got tab complete too. So something like /subsystem=logging/root-logger=<TAB> or /subsystem=logging:<TAB> will auto-complete or show you all the options.

                           

                          --

                          James R. Perkins

                          • 10. Re: Wildfly 10.0.0 Accessing CLI programmatically
                            delphinus818

                            Hi James, what is the syntax to obtain all the loggers defined (example below)?   Since I don’t know all the categories ahead of time, I can’t pass in the name of the category but will have to obtain the categories at runtime.  Thanks

                             

                            <logger category="com.arjuna">

                                    <level name="WARN"/>

                            </logger>

                            <logger category="com.google">

                                    <level name="WARN"/>

                            </logger>

                            • 11. Re: Wildfly 10.0.0 Accessing CLI programmatically
                              jamezp

                              I'm not sure I really follow what you're asking. Do you want to see what loggers have been configured on the logging subsystem?

                               

                              --

                              James R. Perkins

                              • 12. Re: Wildfly 10.0.0 Accessing CLI programmatically
                                delphinus818

                                Thank you for your reply, James.  I’ve figured out the answer since then:

                                 

                                  ModelNode op = new ModelNode();

                                        op.get("operation").set("read-resource");

                                 

                                        ModelNode address = op.get("address");

                                        address.add("subsystem", "logging");

                                        address.add("logger", "*");