~crossbar/crossbar/trunk

« back to all changes in this revision

Viewing changes to crossbar/controller/cli.py

  • Committer: Tobias Oberstein
  • Date: 2015-08-08 17:33:16 UTC
  • mfrom: (768.1.43)
  • Revision ID: git-v1:d3b417ac7448176393afb2435b1d90669b6e629d
Merge pull request #380 from hawkowl/clitests

Test the CLI + make sure file logging actually works (especially on Py3) + make the CLI logger start on all functions

Show diffs side-by-side

added added

removed removed

Lines of Context:
47
47
from autobahn.twisted.choosereactor import install_reactor
48
48
 
49
49
import crossbar
 
50
from crossbar._logging import make_logger
 
51
 
50
52
 
51
53
try:
52
54
    import psutil
132
134
    :returns: The PID of the running Crossbar.io controller process or ``None``
133
135
    :rtype: int or None
134
136
    """
 
137
    log = make_logger()
 
138
 
135
139
    fp = os.path.join(cbdir, _PID_FILENAME)
136
140
    if os.path.isfile(fp):
137
141
        with open(fp) as fd:
143
147
                try:
144
148
                    os.remove(fp)
145
149
                except Exception as e:
146
 
                    print("Could not remove corrupted Crossbar.io PID file {} - {}".format(fp, e))
 
150
                    log.info("Could not remove corrupted Crossbar.io PID file {} - {}".format(fp, e))
147
151
                else:
148
 
                    print("Corrupted Crossbar.io PID file {} removed".format(fp))
 
152
                    log.info("Corrupted Crossbar.io PID file {} removed".format(fp))
149
153
            else:
150
154
                if sys.platform == 'win32' and not _HAS_PSUTIL:
151
155
                    # when on Windows, and we can't actually determine if the PID exists,
162
166
                                nicecmdline = ' '.join(cmdline)
163
167
                                if len(nicecmdline) > 76:
164
168
                                    nicecmdline = nicecmdline[:38] + ' ... ' + nicecmdline[-38:]
165
 
                                print('"{}" points to PID {} which is not a crossbar process:'.format(fp, pid))
166
 
                                print('  ' + nicecmdline)
167
 
                                print('Verify manually and either kill {} or delete {}'.format(pid, fp))
 
169
                                log.info('"{}" points to PID {} which is not a crossbar process:'.format(fp, pid))
 
170
                                log.info('  ' + nicecmdline)
 
171
                                log.info('Verify manually and either kill {} or delete {}'.format(pid, fp))
168
172
                                return None
169
173
                        return pid_data
170
174
                    else:
171
175
                        try:
172
176
                            os.remove(fp)
173
177
                        except Exception as e:
174
 
                            print("Could not remove stale Crossbar.io PID file {} (pointing to non-existing process with PID {}) - {}".format(fp, pid, e))
 
178
                            log.info("Could not remove stale Crossbar.io PID file {} (pointing to non-existing process with PID {}) - {}".format(fp, pid, e))
175
179
                        else:
176
 
                            print("Stale Crossbar.io PID file {} (pointing to non-existing process with PID {}) removed".format(fp, pid))
 
180
                            log.info("Stale Crossbar.io PID file {} (pointing to non-existing process with PID {}) removed".format(fp, pid))
177
181
    return None
178
182
 
179
183
 
180
 
def run_command_version(options):
 
184
def run_command_version(options, **kwargs):
181
185
    """
182
186
    Subcommand "crossbar version".
183
187
    """
268
272
    print("")
269
273
 
270
274
 
271
 
def run_command_templates(options):
 
275
def run_command_templates(options, **kwargs):
272
276
    """
273
277
    Subcommand "crossbar templates".
274
278
    """
278
282
    templates.help()
279
283
 
280
284
 
281
 
def run_command_init(options):
 
285
def run_command_init(options, **kwargs):
282
286
    """
283
287
    Subcommand "crossbar init".
284
288
    """
 
289
    log = make_logger()
 
290
 
285
291
    from crossbar.controller.template import Templates
286
292
 
287
293
    templates = Templates()
288
294
 
289
295
    if options.template not in templates:
290
 
        print("Huh, sorry. There is no template named '{}'. Try 'crossbar templates' to list the templates available.".format(options.template))
 
296
        log.info("Huh, sorry. There is no template named '{options.template}'. Try 'crossbar templates' to list the templates available.",
 
297
                 options=options)
291
298
        sys.exit(1)
292
299
 
293
300
    if options.appdir is None:
301
308
        except Exception as e:
302
309
            raise Exception("could not create application directory '{}' ({})".format(options.appdir, e))
303
310
        else:
304
 
            print("Crossbar.io application directory '{}' created".format(options.appdir))
 
311
            log.info("Crossbar.io application directory '{options.appdir}' created",
 
312
                     options=options)
305
313
 
306
314
    options.appdir = os.path.abspath(options.appdir)
307
315
 
308
 
    print("Initializing application template '{}' in directory '{}'".format(options.template, options.appdir))
 
316
    log.info("Initializing application template '{options.template}' in directory '{options.appdir}'",
 
317
             options=options)
309
318
    get_started_hint = templates.init(options.appdir, options.template)
310
319
 
311
 
    # try:
312
 
    #    templates.init(options.appdir, options.template)
313
 
    # except Exception as e:
314
 
    #    try:
315
 
    #       shutil.rmtree(options.appdir)
316
 
    #    except:
317
 
    #       pass
318
 
    #    raise e
 
320
    log.info("Application template initialized")
319
321
 
320
 
    print("Application template initialized")
321
322
    if get_started_hint:
322
 
        print("\n{}\n".format(get_started_hint))
 
323
        log.info("\n{}\n".format(get_started_hint))
323
324
    else:
324
 
        print("\nTo start your node, run 'crossbar start --cbdir {}'\n".format(os.path.abspath(os.path.join(options.appdir, '.crossbar'))))
325
 
 
326
 
 
327
 
def run_command_status(options):
 
325
        log.info("\nTo start your node, run 'crossbar start --cbdir {cbdir}'\n",
 
326
                 cbdir=os.path.abspath(os.path.join(options.appdir, '.crossbar')))
 
327
 
 
328
 
 
329
def run_command_status(options, **kwargs):
328
330
    """
329
331
    Subcommand "crossbar status".
330
332
    """
 
333
    log = make_logger()
 
334
 
331
335
    # check if there is a Crossbar.io instance currently running from
332
336
    # the Crossbar.io node directory at all
333
337
    #
335
339
    if pid_data is None:
336
340
        # https://docs.python.org/2/library/os.html#os.EX_UNAVAILABLE
337
341
        # https://www.freebsd.org/cgi/man.cgi?query=sysexits&sektion=3
338
 
        print("No Crossbar.io instance is currently running from node directory {}.".format(options.cbdir))
 
342
        log.info("No Crossbar.io instance is currently running from node directory {cbdir}.",
 
343
                 cbdir=options.cbdir)
339
344
        sys.exit(getattr(os, 'EX_UNAVAILABLE', 1))
340
345
    else:
341
 
        print("A Crossbar.io instance is running from node directory {} (PID {}).".format(options.cbdir, pid_data['pid']))
 
346
        log.info("A Crossbar.io instance is running from node directory {cbdir} (PID {pid}).",
 
347
                 cbdir=options.cbdir, pid=pid_data['pid'])
342
348
        sys.exit(0)
343
349
 
344
350
 
345
 
def run_command_stop(options, exit=True):
 
351
def run_command_stop(options, exit=True, **kwargs):
346
352
    """
347
353
    Subcommand "crossbar stop".
348
354
    """
379
385
        sys.exit(getattr(os, 'EX_UNAVAILABLE', 1))
380
386
 
381
387
 
382
 
def run_command_start(options):
 
388
def _startlog(options):
 
389
    """
 
390
    Start the logging in a way that all the subcommands can use it.
 
391
    """
 
392
    from crossbar._logging import log_publisher, start_logging
 
393
    from crossbar._logging import set_global_log_level
 
394
 
 
395
    loglevel = getattr(options, "loglevel", "info")
 
396
    logformat = getattr(options, "logformat", "none")
 
397
 
 
398
    set_global_log_level(loglevel)
 
399
 
 
400
    if getattr(options, "logtofile", False):
 
401
        # We want to log to a file
 
402
        from crossbar._logging import make_logfile_observer
 
403
 
 
404
        if not options.logdir:
 
405
            logdir = options.cbdir
 
406
        else:
 
407
            logdir = options.logdir
 
408
 
 
409
        logfile = os.path.join(logdir, "node.log")
 
410
 
 
411
        if loglevel in ["error", "warn", "info"]:
 
412
            show_source = False
 
413
        else:
 
414
            show_source = True
 
415
 
 
416
        log_publisher.addObserver(make_logfile_observer(logfile, show_source))
 
417
    else:
 
418
        # We want to log to stdout/stderr.
 
419
        from crossbar._logging import make_stdout_observer
 
420
        from crossbar._logging import make_stderr_observer
 
421
 
 
422
        if loglevel == "none":
 
423
            # Do no logging!
 
424
            pass
 
425
        elif loglevel in ["error", "warn", "info"]:
 
426
            # Print info to stdout, warn+ to stderr
 
427
            log_publisher.addObserver(make_stdout_observer(show_source=False,
 
428
                                                           format=logformat))
 
429
            log_publisher.addObserver(make_stderr_observer(show_source=False,
 
430
                                                           format=logformat))
 
431
        elif loglevel == "debug":
 
432
            # Print debug+info to stdout, warn+ to stderr, with the class
 
433
            # source
 
434
            log_publisher.addObserver(make_stdout_observer(show_source=True,
 
435
                                                           format=logformat))
 
436
            log_publisher.addObserver(make_stderr_observer(show_source=True,
 
437
                                                           format=logformat))
 
438
        elif loglevel == "trace":
 
439
            # Print trace+, with the class source
 
440
            log_publisher.addObserver(make_stdout_observer(show_source=True,
 
441
                                                           format=logformat,
 
442
                                                           trace=True))
 
443
            log_publisher.addObserver(make_stderr_observer(show_source=True,
 
444
                                                           format=logformat))
 
445
        else:
 
446
            assert False, "Shouldn't ever get here."
 
447
 
 
448
    # Actually start the logger.
 
449
    start_logging()
 
450
 
 
451
 
 
452
def run_command_start(options, reactor=None):
383
453
    """
384
454
    Subcommand "crossbar start".
385
455
    """
395
465
        with open(fp, 'w') as fd:
396
466
            argv = options.argv
397
467
            options_dump = vars(options)
398
 
            del options_dump['func']
399
 
            del options_dump['argv']
400
468
            pid_data = {
401
469
                'pid': os.getpid(),
402
470
                'argv': argv,
403
 
                'options': options_dump
 
471
                'options': {x: y for x, y in options_dump.items()
 
472
                            if x not in ["func", "argv"]}
404
473
            }
405
474
            fd.write("{}\n".format(json.dumps(pid_data, sort_keys=False, indent=3, separators=(',', ': '))))
406
475
 
407
 
    # we use an Autobahn utility to import the "best" available Twisted reactor
408
 
    #
409
 
    reactor = install_reactor(options.reactor, options.debug)
 
476
    if not reactor:
 
477
        # we use an Autobahn utility to import the "best" available Twisted reactor
 
478
        #
 
479
        reactor = install_reactor(options.reactor, options.debug)
410
480
 
411
481
    # remove node PID file when reactor exits
412
482
    #
416
486
            os.remove(fp)
417
487
    reactor.addSystemEventTrigger('after', 'shutdown', remove_pid_file)
418
488
 
419
 
    # start Twisted logging
420
 
    #
421
 
    from crossbar._logging import log_publisher, make_logger
422
 
    from crossbar._logging import start_logging, set_global_log_level
423
 
 
424
 
    set_global_log_level(options.loglevel)
425
 
 
426
489
    log = make_logger()
427
490
 
428
 
    if options.logtofile:
429
 
        # We want to log to a file
430
 
        from crossbar._logging import make_legacy_daily_logfile_observer
431
 
 
432
 
        if not options.logdir:
433
 
            logdir = options.cbdir
434
 
        else:
435
 
            logdir = options.logdir
436
 
 
437
 
        log_publisher.addObserver(
438
 
            make_legacy_daily_logfile_observer(logdir))
439
 
    else:
440
 
        # We want to log to stdout/stderr.
441
 
        from crossbar._logging import make_stdout_observer
442
 
        from crossbar._logging import make_stderr_observer
443
 
 
444
 
        if options.loglevel == "none":
445
 
            # Do no logging!
446
 
            pass
447
 
        elif options.loglevel in ["error", "warn", "info"]:
448
 
            # Print info to stdout, warn+ to stderr
449
 
            log_publisher.addObserver(make_stdout_observer(show_source=False, format=options.logformat))
450
 
            log_publisher.addObserver(make_stderr_observer(show_source=False, format=options.logformat))
451
 
        elif options.loglevel == "debug":
452
 
            # Print debug+info to stdout, warn+ to stderr, with the class
453
 
            # source
454
 
            log_publisher.addObserver(make_stdout_observer(show_source=True, format=options.logformat))
455
 
            log_publisher.addObserver(make_stderr_observer(show_source=True, format=options.logformat))
456
 
        elif options.loglevel == "trace":
457
 
            # Print trace+, with the class source
458
 
            log_publisher.addObserver(make_stdout_observer(show_source=True, format=options.logformat, trace=True))
459
 
            log_publisher.addObserver(make_stderr_observer(show_source=True, format=options.logformat))
460
 
        else:
461
 
            assert False, "Shouldn't ever get here."
462
 
 
463
 
    # Actually start the logger.
464
 
    start_logging()
465
 
 
 
491
    # Print the banner.
466
492
    for line in BANNER.splitlines():
467
493
        log.info(click.style(("{:>40}").format(line), fg='yellow', bold=True))
468
494
 
508
534
        log.failure("Could not start reactor: {log_failure.value}")
509
535
 
510
536
 
511
 
def run_command_restart(options):
 
537
def run_command_restart(options, **kwargs):
512
538
    """
513
539
    Subcommand "crossbar restart".
514
540
    """
521
547
    run(prog, args)
522
548
 
523
549
 
524
 
def run_command_check(options):
 
550
def run_command_check(options, **kwargs):
525
551
    """
526
552
    Subcommand "crossbar check".
527
553
    """
540
566
        sys.exit(0)
541
567
 
542
568
 
543
 
def run_command_convert(options):
 
569
def run_command_convert(options, **kwargs):
544
570
    """
545
571
    Subcommand "crossbar convert".
546
572
    """
558
584
        sys.exit(0)
559
585
 
560
586
 
561
 
def run(prog=None, args=None):
 
587
def run(prog=None, args=None, reactor=None):
562
588
    """
563
589
    Entry point of Crossbar.io CLI.
564
590
    """
768
794
                    print("Could not create log directory: {}".format(e))
769
795
                    sys.exit(1)
770
796
 
 
797
    # Start the logger
 
798
    _startlog(options)
 
799
 
771
800
    # run the subcommand selected
772
801
    #
773
 
    options.func(options)
 
802
    options.func(options, reactor=reactor)
774
803
 
775
804
 
776
805
if __name__ == '__main__':