示例#1
0
文件: logger.c 项目: Petzku/weechat
int
weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[])
{
    /* make C compiler happy */
    (void) argc;
    (void) argv;

    weechat_plugin = plugin;

    if (!logger_config_init ())
        return WEECHAT_RC_ERROR;

    logger_config_read ();

    /* command /logger */
    weechat_hook_command (
        "logger",
        N_("logger plugin configuration"),
        N_("list"
           " || set <level>"
           " || flush"
           " || disable"),
        N_("   list: show logging status for opened buffers\n"
           "    set: set logging level on current buffer\n"
           "  level: level for messages to be logged (0 = logging disabled, "
           "1 = a few messages (most important) .. 9 = all messages)\n"
           "  flush: write all log files now\n"
           "disable: disable logging on current buffer (set level to 0)\n"
           "\n"
           "Options \"logger.level.*\" and \"logger.mask.*\" can be used to set "
           "level or mask for a buffer, or buffers beginning with name.\n"
           "\n"
           "Log levels used by IRC plugin:\n"
           "  1: user message, notice, private\n"
           "  2: nick change\n"
           "  3: server message\n"
           "  4: join/part/quit\n"
           "  9: all other messages\n"
           "\n"
           "Examples:\n"
           "  set level to 5 for current buffer:\n"
           "    /logger set 5\n"
           "  disable logging for current buffer:\n"
           "    /logger disable\n"
           "  set level to 3 for all IRC buffers:\n"
           "    /set logger.level.irc 3\n"
           "  disable logging for main WeeChat buffer:\n"
           "    /set logger.level.core.weechat 0\n"
           "  use a directory per IRC server and a file per channel inside:\n"
           "    /set logger.mask.irc \"$server/$channel.weechatlog\""),
        "list"
        " || set 1|2|3|4|5|6|7|8|9"
        " || flush"
        " || disable",
        &logger_command_cb, NULL);

    logger_start_buffer_all (1);

    weechat_hook_signal ("buffer_opened", &logger_buffer_opened_signal_cb, NULL);
    weechat_hook_signal ("buffer_closing", &logger_buffer_closing_signal_cb, NULL);
    weechat_hook_signal ("buffer_renamed", &logger_buffer_renamed_signal_cb, NULL);
    weechat_hook_signal ("logger_backlog", &logger_backlog_signal_cb, NULL);
    weechat_hook_signal ("logger_start", &logger_start_signal_cb, NULL);
    weechat_hook_signal ("logger_stop", &logger_stop_signal_cb, NULL);
    weechat_hook_signal ("day_changed", &logger_day_changed_signal_cb, NULL);

    weechat_hook_print (NULL, NULL, NULL, 1, &logger_print_cb, NULL);

    logger_info_init ();

    return WEECHAT_RC_OK;
}
示例#2
0
/**
 * Starts the harness.
 *
 * \param argc Num of args
 * \param argv The args
 * \returns 0 on success, -1 on error
 */
int main(int argc, char *argv[])
{
  SHORT_PROCESS_NAME = basename_safe(argv[0]);
  PROCESS_NAME = argv[0];

  // We accept only one argument, namely the transport address of the
  // global configuration server
  if (argc != 2)
  {
    print_usage();
    return -1;
  }

  if (config_init(argv[1]) != 0)
  {
    error_log("Unable to setup test harness. Is there a problem with the endpoint syntax? %s", argv[1]);
    return -1;
  }

  int ret = 0;

  ret = logger_config_init();

  if (ret != 0)
  {
    error_log("Failed to create log transport");
    cleanup(NULL);
    return -1;
  }

  char *test_harness_listen_endpoint = g_strdup_printf("%s-%d", TEST_SOCKET, getpid());

  debug_log("Test harness is listening on %s", test_harness_listen_endpoint);
  transport_t transport = transport_init(TRANSPORT_TYPE_PUSHPULL, test_harness_listen_endpoint);

  if (transport == NULL)
  {
    error_log("Unable to create transport");
    g_free(test_harness_listen_endpoint);
    cleanup(NULL);
    return -1;
  }

  if (spawn_subcontractor(argv[1], test_harness_listen_endpoint) != 0)
  {
    error_log("Unable to spawn subcontractor");
    g_free(test_harness_listen_endpoint);
    cleanup(transport);
    return -1;
  }
  g_free(test_harness_listen_endpoint);
  test_harness_listen_endpoint = NULL;

  char *input_file;

  if ((config_get(NULL, CONFIG_INPUT_FILE_OPTION_NAME, &input_file) != 0) || (input_file == NULL))
  {
    error_log("Could not get input file name");
    cleanup(transport);
    return -1;
  }

  char *subcontractor;

  if ((config_get(NULL, CONFIG_TEST_HARNESS_SUBCONTRACTOR_TO_TEST_OPTION_NAME, &subcontractor) != 0) || (subcontractor == NULL))
  {
    error_log("Unable to get the name of the subcontractor which means I couldn't calculate the timeout!");
    return -1;
  }

  const char *sub_name = basename_safe(subcontractor);

  long timeout = CONFIG_CONTRACTOR_SUBCONTRACTOR_TRANSPORT_TIMEOUT_DEFAULT;

  if (config_get_long_group_or_general_with_default_macro(sub_name, CONFIG_CONTRACTOR_SUBCONTRACTOR_TRANSPORT_TIMEOUT, &timeout) != 0)
  {
    info_log("Couldn't find out what timeout option to use, using default");
  }

  transport_set_recv_timeout(transport, timeout);
  debug_log("Using %li for timeout to subcontractor", timeout);

  unsigned int contract_string_size;
  contract_t c = contract_init(NULL, 0);

  contract_set_path(c, input_file);
  contract_set_contiguous(c, 1);
  contract_set_absolute_offset(c, 0);
  char *contract_string = contract_serialise(c, &contract_string_size);

  contract_close(c);
  g_free(input_file);
  if (contract_string == NULL)
  {
    perror("Failed to create contract_string");
    g_free(contract_string);
    g_free(subcontractor);
    cleanup(transport);
    return -1;
  }

  info_log("Sending message");

  unsigned int subcontractor_result_msg_size;
  const char *subcontractor_result_msg = transport_sendrecv(transport, contract_string, contract_string_size, &child_pid, &subcontractor_result_msg_size);

  if (subcontractor_result_msg == NULL)
  {

    if (errno == EAGAIN)
    {
      // Timeout.
      error_log
        ("Timeout in receiving message from subcontractor! Either your subcontractor hung (it will be killed when running in pronghorn) or it didn't compelete in time. You need to make sure that the timeout is long enough, by setting subcontractor_timeout (specifcally for your sub contractor or the general case). In pronghorn, this would be via the config file. Using the test harness, you can specificy this using \"-o %s.subcontractor_timeout=<timeout in milliseconds>\" or \"-o general.subcontractor_timeout=<timeout in milliseconds>\" at the end of the command line",
         sub_name);

    } else if (errno == EINTR)
    {
      // Interupted.
      error_log("Something when wrong waiting for your subcontractor to return. Did it crash?! You might like to try adding \"-o %s.valgrind_opts=<path to valgrind>\" when testing.", sub_name);
    }

    cleanup(transport);
    g_free(contract_string);
    g_free(subcontractor);
    return -1;
  }

  g_free(subcontractor);

  contract_completion_report_t report = contract_completion_report_init(subcontractor_result_msg, subcontractor_result_msg_size);

  if (report == NULL)
  {
    perror("Recreating contract_completion_report");
    g_free(contract_string);
    cleanup(transport);
    return -1;
  } else
  {
    info_log("Reconstructed message");
  }

  info_log("=====================");
  info_log("Results: ");
  unsigned int results_count;
  const result_t *results = contract_completion_report_get_results(report, &results_count);

  c = contract_completion_report_get_original_contract(report);;

  for (int i = 0; i < results_count; i++)
  {
    const result_t r = results[i];

    info_log("Path=%s. Type=(%s) %s. Confidence=%d", contract_get_path(c), result_get_brief_data_description(r), result_get_data_description(r), result_get_confidence(r));

#if PRINT_BLOCK_ARRAY
    unsigned int block_range_size;
    const block_range_t *ranges = result_get_block_ranges(r, &block_range_size);

    if (block_range_size > 0)
    {
      int j;

      info_log("Blocks:");

      // This is inefficient. But it works and this function is rarely used
      char *big_s = g_strdup("");

      for (j = 0; j < block_range_size; j++)
      {
        unsigned long long pos;
        unsigned long long len;

        block_range_get_range(ranges[j], &pos, &len);
        char *new_s = g_strdup_printf("%s %llu-%llu", big_s, pos, pos + len - 1);

        g_free(big_s);
        big_s = new_s;
      }
      info_log("%s", big_s);
      g_free(big_s);
    }
#endif // PRINT_BLOCK_ARRAY

    unsigned int new_contracts_count;

#if SIMPLE_CONTRACT_ENUMERATION
    result_get_new_contracts(r, &new_contracts_count);

    info_log("\t- With %d new contracts!", new_contracts_count);
#else // SIMPLE_CONTRACT_ENUMERATION
    // Yes, this looks dodgy, but it's fine until r gets destroyed (which is after we destroy our copy)
    const contract_t *new_contracts_const = result_get_new_contracts(r, &new_contracts_count);
    contract_t *new_contracts = (contract_t *) g_malloc(sizeof(contract_t) * new_contracts_count);

    memcpy(new_contracts, new_contracts_const, sizeof(contract_t) * new_contracts_count);

    if (new_contracts_count > 0)
    {
      // Sorting the array
#if SORT_CONTRACT_ARRAY
      {
        int j;

        for (j = 0; j < new_contracts_count - 1; j++)
        {
          int k;

          for (k = 0; k < new_contracts_count - j - 1; k++)
          {
            int a = atoi(contract_get_path(new_contracts[k]));
            int b = atoi(contract_get_path(new_contracts[k + 1]));

            if (a > b)
            {
              contract_t temp = new_contracts[k];

              new_contracts[k] = new_contracts[k + 1];
              new_contracts[k + 1] = temp;
            } else if (a == b)
            {
              warning_log("Duplicate entry found! %s", contract_get_path(new_contracts[k]));
            }
          }
        }
      }
#endif // SORT_CONTRACT_ARRAY
#if PRINT_CONTRACT_ARRAY
      {
        info_log("New contracts: ");
        int j;

        for (j = new_contracts_count - 1; j >= 0; j--)
        {
          const char *path = contract_get_path(new_contracts[j]);

          if (access(path, R_OK) == 0)
          {
            info_log("OK %s", path);
            print_md5(path);
          } else
          {
            info_log("Couldn't access advertised new path %s", path);
          }
        }
      }
#endif // PRINT_CONTRACT_ARRAY
    }
    g_free(new_contracts);
#endif // SIMPLE_CONTRACT_ENUMERATION
  }
  contract_completion_report_close(report);


  if (NUM_EXERCISE_LOOPS != 0)
  {
    info_log("=====================");
    info_log("Exercising the plugin");
    for (int i = 0; i < NUM_EXERCISE_LOOPS; i++)
    {
      subcontractor_result_msg = transport_sendrecv(transport, (char *) contract_string, contract_string_size, &child_pid, &subcontractor_result_msg_size);
    }

    info_log("Finished exercising the plugin");
  }

  info_log("=====================");

  info_log("Telling subcontractor to close nicely");

  g_free(contract_string);

  // Send empty contract to tell child to close
  c = contract_init(NULL, 0);
  contract_set_path(c, "");
  contract_string = contract_serialise(c, &contract_string_size);
  contract_close(c);
  subcontractor_result_msg = transport_sendrecv(transport, (char *) contract_string, contract_string_size, &child_pid, &subcontractor_result_msg_size);
  g_free(contract_string);

  if (child_pid != -1)
  {
    sleep(100);
  }

  volatile int local_child_pid = child_pid;

  if (local_child_pid != -1)
  {
    warning_log("Process hasn't died automatically. Sending SIGTERM");
    kill(local_child_pid, SIGTERM);
    sleep(10);
    local_child_pid = child_pid;
    if (local_child_pid != -1)
    {
      warning_log("Process STILL hasn't died... Killing it");
      kill(local_child_pid, SIGKILL);
    }
  }

  cleanup(transport);

  return 0;
}