# Internal code configuration files

Sbws has two default config files it reads: one general, and one specific to logging. They all get combined internally to the same `conf` structure.

It first reads the config file containing the default values for almost all options. If you installed sbws in a virtual environment located at /tmp/venv, then you will probably find the `config.default.ini` in a place such as `/tmp/venv/lib/python3.5/site-packages/sbws/` You should never edit this file. The contents of this default config file can be found at the bottom of this page.

Second, `sbws` will read `config.log.default.ini`. It will be located in the same place as the previous file, and should not be edited like the previous file. The contents of this default log config file can be found at the bottom of this page. Options set here overwrite options set in the previous config file.

Sbws then reads your custom config file. By default, it will search for it in `~/.sbws.ini`. Options in this file overwrite options set in previously read config files.

The user example config file provided by `sbws` might look like this.

Listing 2 Example sbws.example.ini

    # Minimum configuration that needs to be customized
    [scanner]
    # A human-readable string with chars in a-zA-Z0-9 to identify your scanner
    nickname = sbws_default
    # ISO 3166-1 alpha-2 country code where the Web server destination is located.
    # Default AA, to detect it was not edited.
    country = SN

    [destinations]
    # With several destinations, the scanner can continue even if some of them
    # fail, which can be caused by a network problem on their side.
    # If all of them fail, the scanner will stop, which
    # will happen if there is network problem on the scanner side.

    # A destination can be disabled changing `on` by `off`
    foo = on

    [destinations.foo]
    # the domain and path to the 1GB file.
    url = https://example.com/does/not/exist.bin
    # Whether to verify or not the TLS certificate. Default True
    verify = False
    # ISO 3166-1 alpha-2 country code where the Web server destination is located.
    # Default AA, to detect it was not edited.
    # Use ZZ if the location is unknown (for instance, a CDN).
    country = ZZ

    # Number of consecutive times that a destination could not be used to measure
    # before stopping to try to use it for a while that by default is 3h.
    max_num_failures = 3

    ## The following logging options are set by default.
    ## There is no need to change them unless other options are preferred.
    ; [logging]
    ; # Whether or not to log to a rotating file the directory paths.log_dname
    ; to_file = yes
    ; # Whether or not to log to stdout
    ; to_stdout = yes
    ; # Whether or not to log to syslog
    ; # NOTE that when sbws is launched by systemd, stdout goes to journal and
    ; # syslog.
    ; to_syslog = no

    ; # Level to log at. Debug, info, warning, error, critical.
    ; # `level` must be set to the lower of all the handler levels.
    ; level = debug
    ; to_file_level = debug
    ; to_stdout_level = info
    ; to_syslog_level = info
    ; # Format string to use when logging
    ; format = %(module)s[%(process)s]: <%(levelname)s> %(message)s
    ; # verbose formatter useful for debugging
    ; to_file_format = %(asctime)s %(levelname)s %(threadName)s %(filename)s:%(lineno)s - %(funcName)s - %(message)s
    ; # Not adding %(asctime)s to to stdout since it'll go to syslog when using
    ; # systemd, and it'll have already the date.
    ; to_stdout_format = ${format}
    ; to_syslog_format = ${format}

    # To disable certificate validation, uncomment the following
    # verify = False

No other configuration files are read.

## Default Configuration

Listing 3 config.default.ini

    [paths]
    sbws_home = ~/.sbws
    datadir = ${sbws_home}/datadir
    v3bw_dname = ${sbws_home}/v3bw
    # The latest bandwidth file is atomically symlinked to
    # V3BandwidthsFile ${v3bw_dname}/latest.v3bw
    v3bw_fname = ${v3bw_dname}/{}.v3bw
    state_fname = ${sbws_home}/state.dat
    log_dname = ${sbws_home}/log

    [destinations]
    # How often to check if a destional is usable
    usability_test_interval = 300

    [general]
    # Days into the past that measurements are considered valid
    data_period = 5
    # Timeout in seconds to give to the python Requests library. It MUST be a
    # single float. Requests will use it both as the connect() timeout and the
    # timeout between bytes received from the server. See
    # http://docs.python-requests.org/en/master/user/advanced/#timeouts
    http_timeout = 10
    # Timeout in seconds for waiting on a circuit to be built. It MUST be an
    # **int**. We will use this both as the CircuitBuildTimeout and a timeout
    # to give to stem for waiting on a circuit to be built since
    # CircuitBuildTimeout doesn't handle the case of a TLS connection to a relay
    # taking forever, and probably other not-yet-discovered cases.
    circuit_timeout = 60
    # Whether or not to reset the bandwidth measurements when the relay's IP
    # address changes. If it changes, we only consider results for the relay that
    # we obtained while the relay was located at its most recent IP address.
    # This is NOT implemented for IPv6.
    reset_bw_ipv4_changes = off
    reset_bw_ipv6_changes = off

    [scanner]
    # A human-readable string with chars in a-zA-Z0-9 to identify your scanner
    nickname = IDidntEditTheSBWSConfig
    # ISO 3166-1 alpha-2 country code. To be edited.
    # Default to a non existing country to detect it was not edited.
    country = AA
    # Limits on what download times are too fast/slow/etc.
    download_toofast = 1
    download_min = 5
    download_target = 6
    download_max = 10
    # How many RTT measurements to make
    num_rtts = 0
    # Number of downloads with acceptable times we must have for a relay before
    # moving on
    num_downloads = 5
    # The number of bytes to initially request from the server
    initial_read_request = 16384
    # How many measurements to make in parallel
    measurement_threads = 3
    # Minimum number of bytes we should ever try to download in a measurement
    min_download_size = 1
    # Maximum number of bytes we should ever try to download in a measurement
    # 1073741824 == 1 GiB
    max_download_size = 1073741824

    [tor]
    datadir = ${paths:sbws_home}/tor
    run_dpath = ${datadir}
    control_socket = ${tor:run_dpath}/control
    pid = ${tor:run_dpath}/tor.pid
    # note this is a directory
    log = ${tor:datadir}/log
    external_control_port =
    extra_lines =

    [cleanup]
    # After this many days, compress data files
    # #40017: To generate files as Torflow the result files must be kept for
    # GENERATE_PERIOD seconds.
    # The number of days after they are compressed or deleted could be added
    # as defaults (currently globals.py), and just as a factor of GENERATE_PERIOD.
    data_files_compress_after_days = 29
    # After this many days, delete data files.
    # 57 == 28 * 2 + 1.
    data_files_delete_after_days = 57
    # After this many days, compress v3bw files (1d)
    v3bw_files_compress_after_days = 1
    # After this many days, delete v3bw files (7d)
    v3bw_files_delete_after_days = 7

    [relayprioritizer]
    # Whether or not to measure authorities
    measure_authorities = off
    # The target fraction of best priority relays we would like to return.
    # 0.05 is 5%. In a 7000 relay network, 5% is 350 relays.
    #
    # In a network of ~6500 relays and with a ResultDump containing 1 result per
    # relay, the best_priority() function takes ~11 seconds to complete on my
    # home desktop. Using this parameter allows us to balance between calling
    # best_priority() more often (but wasting more CPU), and calling it less
    # often (but taking longer to get back to relays with non-successful results).
    #
    # Alternatively, we could rewrite best_priority() to not suck so much.
    fraction_relays = 0.05
    # The minimum number of best priority relays we are willing to return
    min_relays = 50

    [logging]
    # Whether or not to log to a rotating file the directory paths.log_dname
    to_file = yes
    # Whether or not to log to stdout
    to_stdout = yes
    # Whether or not to log to syslog
    # NOTE that when sbws is launched by systemd, stdout goes to journal and
    # syslog.
    to_syslog = no
    # If logging to file, how large (in bytes) should the file be allowed to get
    # before rotating to a new one. 10485760 is 10 MiB. If zero or number of
    # backups is zero, never rotate the log file.
    to_file_max_bytes = 10485760
    # If logging to file, how many backups to keep. If zero or max bytes is zero,
    # never rotate the log file.
    to_file_num_backups = 50
    # Level to log at. Debug, info, warning, error, critical.
    # `level` must be set to the lower of all the handler levels.
    level = info
    to_file_level = info
    to_stdout_level = info
    to_syslog_level = info
    # Format string to use when logging
    format = %(asctime)s %(module)s[%(process)s]: <%(levelname)s> (%(threadName)s) %(message)s
    to_stdout_format = ${format}
    to_syslog_format = %(module)s[%(process)s]: <%(levelname)s> %(message)s
    # verbose formatter useful for debugging
    to_file_format = %(asctime)s %(levelname)s (%(threadName)s) %(filename)s:%(lineno)s - %(funcName)s - %(message)s

If you know how to use Python’s logging configuration file format, then you can override or add to what is listed here by editing your config file.

Listing 4 config.log.default.ini

    [loggers]
    keys = root,sbws

    [handlers]
    keys = to_file,to_stdout,to_syslog

    [formatters]
    keys = to_file,to_stdout,to_syslog

    [logger_root]
    level = WARNING
    handlers = to_file
    propagate = 1
    qualname=root

    [logger_sbws]
    propagate = 0
    qualname=sbws

    [handler_to_stdout]
    class = StreamHandler
    formatter = to_stdout
    args = (sys.stdout,)

    [handler_to_file]
    class = handlers.RotatingFileHandler
    formatter = to_file
    args = ('/dev/null', )

    # for logging to system log
    [handler_to_syslog]
    class=handlers.SysLogHandler
    formatter=to_syslog
    args = ('/dev/log',)

    [formatter_to_stdout]
    # format date as syslog and journal
    datefmt = %b %d %H:%M:%S

    [formatter_to_file]
    datefmt = %b %d %H:%M:%S

    [formatter_to_syslog]