読者です 読者をやめる 読者になる 読者になる

カメニッキ

カメとインコと釣りの人です

Apache拡張モジュール「mod_resource_checker」のソースを眺めてる (途中)

はじめに

  • Cのお勉強のいっかんとして取り組んでいます
  • なので、誤った情報である可能性があります
  • 自分用の覚え書き情報が主なので、役に立たないかもしれません

お題

github.com

mod_resource_checker?

Process Resource Logging Module using JSON format into file or piped program.

アクセス毎にApacheプロセスの使用したOSのリソース情報を、JSON形式でログ出力することができます。

[PMAC226S ~/Downloads]$ tail -1 resource.log | jq .
{
  "module": "mod_resource_checker",
  "date": "Sun Feb 28 22:53:58 2016",
  "type": "RCheckALL",
  "unit": null,
  "location": "/var/www/*/*/web/",
  "remote_ip": "123.456.789.000",
  "filename": "/var/www/web/wp/index.php",
  "scheme": "http",
  "method": "GET",
  "hostname": "hoge.com",
  "server_ip": "192.168.0.111",
  "uri": "/wp/index.php",
  "real_server_name": null,
  "uid": 1234,
  "size": 418,
  "content_length": 0,
  "status": 200,
  "pid": 16431,
  "threshold": null,
  "response_time": 0,
  "result": {
    "RCheckUCPU": 0.552367,
    "RCheckSCPU": 0.00806,
    "RCheckMEM": 0.644531
  }
}

mod_resource_checker.c 読んでいきます

1. 末尾のモジュールをApacheへ登録する部分

722
723 #ifdef __APACHE24__
724 AP_DECLARE_MODULE(resource_checker) = {
725 #else
726 module AP_MODULE_DECLARE_DATA resource_checker_module = {
727 #endif
728     STANDARD20_MODULE_STUFF, (void *)resource_checker_create_dir_config, /* create per-dir    config structures */
729     NULL,                                                                /* merge  per-dir    config structures */
730     (void *)resource_checker_create_config,                              /* create per-server config structures */
731     NULL,                                                                /* merge  per-server config structures */
732     resource_checker_cmds,                                               /* table of config file commands       */
733     resource_checker_register_hooks                                      /* register hooks                      */
734 };

__APACHE24__ で判定しているのは、Apache2.4とそれ以前で定義方法に差異があるからでしょうか。
728〜732行は http://blog.matsumoto-r.jp/?p=603 を読んでお勉強。
とりあえず今は設定がちゃんとされてますか、の面倒をApache起動時に見るための記述という理解。
リクエストを処理する際に気にするところは、 resource_checker_register_hooks の中で設定されたhook関数群かな

2. 登録されたhook関数

715 static void resource_checker_register_hooks(apr_pool_t *p)
716 {
717   ap_hook_post_config((void *)resource_checker_init, NULL, NULL, APR_HOOK_MIDDLE);
718   ap_hook_access_checker(before_resource_checker, NULL, NULL, APR_HOOK_LAST);
719   ap_hook_fixups(resource_checker_handler, NULL, NULL, APR_HOOK_LAST);
720   ap_hook_log_transaction(after_resource_checker, NULL, NULL, APR_HOOK_LAST);
721 }

ap_hook_XXXX はhookさせたいタイミングに応じて、様々な種類がある。詳細は http://d.hatena.ne.jp/dayflower/20081029/1225266220http://blog.matsumoto-r.jp/?p=1625 にまとまっている。 今回のものでいくと、

  • ap_hook_post_config - 設定初期化時
  • ap_hook_access_checker - アクセス制御を行う前(なので、アクセス制御をおこなう)
  • ap_hook_fixups - よくわからん・・・
  • ap_hook_log_transaction - レスポンス後のロギング処理時

今回の mod_resource_checker はリソース情報をロギングすることが目的なので、 ap_hook_log_transaction が重要な仕事をやってそう。

3. ap_hook_log_transaction でやっていること

577 static int after_resource_checker(request_rec *r)
578  {
579    mod_rc_dir_conf *dconf = (mod_rc_dir_conf *)ap_get_module_config(r->per_dir_config, &resource_checker_module);
580    mod_rc_conf *sconf = (mod_rc_conf *)ap_get_module_config(r->server->module_config, &resource_checker_module);
581    mod_rc_rusage *before_resources = dconf->before_resources;
582
583    if (dconf->cpu_utime == INITIAL_VALUE && dconf->cpu_stime == INITIAL_VALUE && dconf->shared_mem == INITIAL_VALUE &&
584        dconf->check_status == OFF && dconf->check_all == OFF)
585      return DECLINED;
586
587    int match;
588    struct stat sb;
589    mod_rc_rusage *after_resources;
590    after_resources = (mod_rc_rusage *)apr_pcalloc(r->pool, sizeof(mod_rc_rusage));
591    mod_rc_rusage *use_resources;
592    use_resources = (mod_rc_rusage *)apr_pcalloc(r->pool, sizeof(mod_rc_rusage));
593
594    mod_rc_client_data *cdata;
595    cdata = (mod_rc_client_data *)apr_pcalloc(r->pool, sizeof(mod_rc_client_data));
596
597    if (resource_checker_initialized == 0) {
598      return OK;
599    }
600
601    if (r->main && (stat(r->filename, &sb) == -1) && errno == ENOENT) {
602      return OK;
603    }
604
605    cdata->access_uri = r->uri;
606    cdata->access_file = r->filename;
607  #ifdef __APACHE24__
608    cdata->access_src_ip = r->connection->client_ip;
609  #else
610    cdata->access_src_ip = r->connection->remote_ip;
611  #endif
612    cdata->access_dst_host = r->server->server_hostname;
613
614    if (dconf->check_status == ON) {
615      _mod_resource_checker_logging(r, 0, 0, NULL, dconf, cdata, MODULE_NAME, "RCheckSTATUS", NULL, r->pool);
616    }
617
618    // threashould check
619    if (before_resources == NULL) {
620      ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, "%s NOTICE %s: Can not check resource of the request: file = %s",
621                    MODULE_NAME, __func__, r->filename);
622      return DECLINED;
623    }
624
625    match = 0;
626    after_resources->cpu_utime = INITIAL_VALUE;
627    after_resources->cpu_stime = INITIAL_VALUE;
628    after_resources->shared_mem = INITIAL_VALUE;
629
630    if (dconf->cpu_utime > INITIAL_VALUE || dconf->check_all == ON) {
631      match = 1;
632      if (dconf->check_all == ON)
633        after_resources->cpu_utime = _get_rusage_resource(r->pool, "ALL", "cpu_utime");
634      else
635        after_resources->cpu_utime = _get_rusage_resource(r->pool, dconf->utime_process_type, "cpu_utime");
636    }
637
638    if (dconf->cpu_stime > INITIAL_VALUE || dconf->check_all == ON) {
639      match = 1;
640      if (dconf->check_all == ON)
641        after_resources->cpu_stime = _get_rusage_resource(r->pool, "ALL", "cpu_stime");
642      else
643        after_resources->cpu_stime = _get_rusage_resource(r->pool, dconf->stime_process_type, "cpu_stime");
644    }
645
646    if (dconf->shared_mem > INITIAL_VALUE || dconf->check_all == ON) {
647      match = 1;
648      if (dconf->check_all == ON)
649        after_resources->shared_mem = _get_rusage_resource(r->pool, "ALL", "shared_mem");
650      else
651        after_resources->shared_mem = _get_rusage_resource(r->pool, dconf->mem_process_type, "shared_mem");
652    }
653
654    if (match == 0) {
655      return OK;
656    }
657
658    use_resources->cpu_utime = after_resources->cpu_utime - before_resources->cpu_utime;
659    use_resources->cpu_stime = after_resources->cpu_stime - before_resources->cpu_stime;
660    use_resources->shared_mem = after_resources->shared_mem - before_resources->shared_mem;
661
662    // unexpected value; resource is negative number
663    if (use_resources->cpu_utime < 0) {
664      use_resources->cpu_utime = 0;
665    }
666    if (use_resources->cpu_stime < 0) {
667      use_resources->cpu_stime = 0;
668    }
669    if (use_resources->shared_mem < 0) {
670      use_resources->shared_mem = 0;
671    }
672
673    if (dconf->cpu_utime > INITIAL_VALUE && use_resources->cpu_utime >= dconf->cpu_utime) {
674      _mod_resource_checker_logging(r, use_resources->cpu_utime, dconf->cpu_utime, dconf->utime_process_type, dconf,
675                                    cdata, MODULE_NAME, "RCheckUCPU", "sec", r->pool);
676    }
677
678    if (dconf->cpu_stime > INITIAL_VALUE && use_resources->cpu_stime >= dconf->cpu_stime) {
679      _mod_resource_checker_logging(r, use_resources->cpu_stime, dconf->cpu_stime, dconf->stime_process_type, dconf,
680                                    cdata, MODULE_NAME, "RCheckSCPU", "sec", r->pool);
681    }
682
683    if (dconf->shared_mem > INITIAL_VALUE && use_resources->shared_mem >= dconf->shared_mem) {
684      _mod_resource_checker_logging(r, use_resources->shared_mem, dconf->shared_mem, dconf->mem_process_type, dconf,
685                                    cdata, MODULE_NAME, "RCheckMEM", "MiB", r->pool);
686    }
687
688    if (dconf->check_all == ON && dconf->json_fmt == ON) {
689      _mod_resource_checker_logging_all(r, use_resources, dconf, sconf, cdata, r->pool);
690    }
691
692    return OK;
693  }

アクセス元IP・CPU使用量・メモリ使用量などかきあつめて、どこまで記録するかの設定に応じてロギング関数に投げてるのかな。

メモ

  • 下部のモジュール定義の書き方、処理させたいタイミングに応じてhook関数を設定する、というやり方は他のApacheモジュールでも同じっぽくて、今後読むときはそこから見ていこう
  • 様々なhookさせるポイントがあって、むずかしい。
  • 調べてもあんまり情報でてこなくて辛い

ほとんど独り言みたいな内容になってしまった。おしまい