~notmyname/swift/deslogging

« back to all changes in this revision

Viewing changes to swift/stats/account_stats.py

  • Committer: Tarmac
  • Author(s): David Goetz, Jay Payne
  • Date: 2011-05-18 15:48:17 UTC
  • mfrom: (286.3.22 containerstat)
  • Revision ID: tarmac-20110518154817-n03d5aig142496q2
Adding container stats collector, unit tests, and refactoring some of the stats code.  There will have to be changes to both the swift and rackswift conf files before this can be released.  Please DO NOT approve this branch for merge until glange's stats stuff is all ready to go.  gracias.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (c) 2010-2011 OpenStack, LLC.
2
 
#
3
 
# Licensed under the Apache License, Version 2.0 (the "License");
4
 
# you may not use this file except in compliance with the License.
5
 
# You may obtain a copy of the License at
6
 
#
7
 
#    http://www.apache.org/licenses/LICENSE-2.0
8
 
#
9
 
# Unless required by applicable law or agreed to in writing, software
10
 
# distributed under the License is distributed on an "AS IS" BASIS,
11
 
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12
 
# implied.
13
 
# See the License for the specific language governing permissions and
14
 
# limitations under the License.
15
 
 
16
 
import os
17
 
import time
18
 
from paste.deploy import appconfig
19
 
import shutil
20
 
import hashlib
21
 
 
22
 
from swift.account.server import DATADIR as account_server_data_dir
23
 
from swift.common.db import AccountBroker
24
 
from swift.common.utils import renamer, get_logger, readconf, mkdirs
25
 
from swift.common.constraints import check_mount
26
 
from swift.common.daemon import Daemon
27
 
 
28
 
 
29
 
class AccountStat(Daemon):
30
 
    """
31
 
    Extract storage stats from account databases on the account
32
 
    storage nodes
33
 
    """
34
 
 
35
 
    def __init__(self, stats_conf):
36
 
        super(AccountStat, self).__init__(stats_conf)
37
 
        target_dir = stats_conf.get('log_dir', '/var/log/swift')
38
 
        account_server_conf_loc = stats_conf.get('account_server_conf',
39
 
                                             '/etc/swift/account-server.conf')
40
 
        server_conf = appconfig('config:%s' % account_server_conf_loc,
41
 
                                name='account-server')
42
 
        filename_format = stats_conf['source_filename_format']
43
 
        if filename_format.count('*') > 1:
44
 
            raise Exception('source filename format should have at max one *')
45
 
        self.filename_format = filename_format
46
 
        self.target_dir = target_dir
47
 
        mkdirs(self.target_dir)
48
 
        self.devices = server_conf.get('devices', '/srv/node')
49
 
        self.mount_check = server_conf.get('mount_check', 'true').lower() in \
50
 
                              ('true', 't', '1', 'on', 'yes', 'y')
51
 
        self.logger = \
52
 
            get_logger(stats_conf, log_route='account-stats')
53
 
 
54
 
    def run_once(self, *args, **kwargs):
55
 
        self.logger.info(_("Gathering account stats"))
56
 
        start = time.time()
57
 
        self.find_and_process()
58
 
        self.logger.info(
59
 
            _("Gathering account stats complete (%0.2f minutes)") %
60
 
            ((time.time() - start) / 60))
61
 
 
62
 
    def find_and_process(self):
63
 
        src_filename = time.strftime(self.filename_format)
64
 
        working_dir = os.path.join(self.target_dir, '.stats_tmp')
65
 
        shutil.rmtree(working_dir, ignore_errors=True)
66
 
        mkdirs(working_dir)
67
 
        tmp_filename = os.path.join(working_dir, src_filename)
68
 
        hasher = hashlib.md5()
69
 
        with open(tmp_filename, 'wb') as statfile:
70
 
            # csv has the following columns:
71
 
            # Account Name, Container Count, Object Count, Bytes Used
72
 
            for device in os.listdir(self.devices):
73
 
                if self.mount_check and not check_mount(self.devices, device):
74
 
                    self.logger.error(
75
 
                        _("Device %s is not mounted, skipping.") % device)
76
 
                    continue
77
 
                accounts = os.path.join(self.devices,
78
 
                                        device,
79
 
                                        account_server_data_dir)
80
 
                if not os.path.exists(accounts):
81
 
                    self.logger.debug(_("Path %s does not exist, skipping.") %
82
 
                        accounts)
83
 
                    continue
84
 
                for root, dirs, files in os.walk(accounts, topdown=False):
85
 
                    for filename in files:
86
 
                        if filename.endswith('.db'):
87
 
                            db_path = os.path.join(root, filename)
88
 
                            broker = AccountBroker(db_path)
89
 
                            if not broker.is_deleted():
90
 
                                (account_name,
91
 
                                _junk, _junk, _junk,
92
 
                                container_count,
93
 
                                object_count,
94
 
                                bytes_used,
95
 
                                _junk, _junk) = broker.get_info()
96
 
                                line_data = '"%s",%d,%d,%d\n' % (
97
 
                                    account_name, container_count,
98
 
                                    object_count, bytes_used)
99
 
                                statfile.write(line_data)
100
 
                                hasher.update(line_data)
101
 
        file_hash = hasher.hexdigest()
102
 
        hash_index = src_filename.find('*')
103
 
        if hash_index < 0:
104
 
            # if there is no * in the target filename, the uploader probably
105
 
            # won't work because we are crafting a filename that doesn't
106
 
            # fit the pattern
107
 
            src_filename = '_'.join([src_filename, file_hash])
108
 
        else:
109
 
            parts = src_filename[:hash_index], src_filename[hash_index + 1:]
110
 
            src_filename = ''.join([parts[0], file_hash, parts[1]])
111
 
        renamer(tmp_filename, os.path.join(self.target_dir, src_filename))
112
 
        shutil.rmtree(working_dir, ignore_errors=True)