0.9.8.10
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Cronolog.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2007-2015 Hypertable, Inc.
3  *
4  * This file is part of Hypertable.
5  *
6  * Hypertable is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; version 3 of the
9  * License, or any later version.
10  *
11  * Hypertable is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  * 02110-1301, USA.
20  */
21 
26 
27 #include <Common/Compat.h>
28 
29 #include "Cronolog.h"
30 
31 #include <Common/FileUtils.h>
32 #include <Common/Logger.h>
33 #include <Common/String.h>
34 
35 #include <boost/algorithm/string.hpp>
36 
37 #include <cerrno>
38 #include <cstdio>
39 
40 extern "C" {
41 #include <fcntl.h>
42 #include <string.h>
43 #include <sys/stat.h>
44 #include <sys/types.h>
45 #include <unistd.h>
46 }
47 
48 using namespace Hypertable;
49 using namespace std;
50 
51 Cronolog::Cronolog(const string &name, const string &current_dir,
52  const string &archive_dir)
53  : m_name(name), m_current_dir(current_dir), m_archive_dir(archive_dir) {
54  boost::trim_right_if(m_current_dir, boost::is_any_of("/"));
55  boost::trim_right_if(m_archive_dir, boost::is_any_of("/"));
56  roll(time(0));
57 }
58 
60  lock_guard<mutex> lock(m_mutex);
61  if (m_fd) {
62  ::close(m_fd);
63  m_fd = 0;
64  }
65 }
66 
67 void Cronolog::write(time_t now, const string &line) {
68  lock_guard<mutex> lock(m_mutex);
69 
70  if (!m_fd)
71  return;
72 
73  if (now >= m_roll_time)
74  roll(now);
75 
76  char buf[32];
77  sprintf(buf, "%d ", (int)now);
78  if (FileUtils::write(m_fd, buf, strlen(buf)) < 0 ||
79  FileUtils::write(m_fd, line) < 0 ||
80  FileUtils::write(m_fd, "\n", 1) < 0)
81  HT_FATALF("write to log file '%s' failed - %s",
82  m_name.c_str(), strerror(errno));
83 
84 }
85 
87  lock_guard<mutex> lock(m_mutex);
88  if (m_fd)
89  ::fsync(m_fd);
90 }
91 
92 void Cronolog::roll(time_t now) {
93 
94  if (m_fd)
95  ::close(m_fd);
96 
97  string linkname = m_current_dir + "/" + m_name;
98 
99  if (FileUtils::exists(linkname)) {
100  if (!FileUtils::unlink(linkname))
101  HT_FATALF("Problem removing link '%s'", linkname.c_str());
102  }
103 
104  struct tm tmval;
105 
106  localtime_r(&now, &tmval);
107 
108  string subdir = format("%s/%d-%02d", m_archive_dir.c_str(),
109  1900 + tmval.tm_year, tmval.tm_mon + 1);
110 
111  if (!FileUtils::exists(subdir)) {
112  if (!FileUtils::mkdirs(subdir))
113  HT_FATALF("Problem creating archive directory '%s'", subdir.c_str());
114  }
115 
116  subdir += format("/%02d", tmval.tm_mday);
117 
118  if (!FileUtils::exists(subdir)) {
119  if (!FileUtils::mkdirs(subdir))
120  HT_FATALF("Problem creating archive directory '%s'", subdir.c_str());
121  }
122 
123  string archive = format("%s/%s", subdir.c_str(), m_name.c_str());
124 
125  m_fd = ::open(archive.c_str(), O_CREAT|O_APPEND|O_WRONLY, 0644);
126  if (m_fd < 0)
127  HT_FATALF("open(%s, O_CREAT|O_APPEND|O_WRONLY, 0644) failed - %s",
128  archive.c_str(), strerror(errno));
129 
130  {
131  char cwd[1024];
132 
133  if (getcwd(cwd, 1024) == nullptr)
134  HT_FATALF("getcwd failure - %s", strerror(errno));
135 
136  if (chdir(m_current_dir.c_str()) < 0)
137  HT_FATALF("chdir(%s) failure - %s", m_current_dir.c_str(), strerror(errno));
138 
139  ::unlink(m_name.c_str());
140 
141  if (symlink(archive.c_str(), m_name.c_str()) < 0)
142  HT_FATALF("symlink(%s, %s) failure - %s", archive.c_str(), m_name.c_str(),
143  strerror(errno));
144 
145  if (chdir(cwd) < 0)
146  HT_FATALF("chdir(%s) failure - %s", cwd, strerror(errno));
147  }
148 
149  tmval.tm_sec = 0;
150  tmval.tm_min = 0;
151  tmval.tm_hour = 0;
152 
153  m_roll_time = mktime(&tmval) + 86400;
154 
155 }
string m_name
Basename of log file.
Definition: Cronolog.h:108
static bool unlink(const String &fname)
Unlinks (deletes) a file or directory.
Definition: FileUtils.cc:427
virtual ~Cronolog()
Destructor.
Definition: Cronolog.cc:59
String format(const char *fmt,...)
Returns a String using printf like format facilities Vanilla snprintf is about 1.5x faster than this...
Definition: String.cc:37
string m_current_dir
Directory containing current symlink of log file.
Definition: Cronolog.h:111
static ssize_t write(const String &fname, const std::string &contents)
Writes a String buffer to a file; the file is overwritten if it already exists.
Definition: FileUtils.cc:124
static bool exists(const String &fname)
Checks if a file or directory exists.
Definition: FileUtils.cc:420
void roll(time_t now)
Rolls the log.
Definition: Cronolog.cc:92
void sync()
Syncs the log file.
Definition: Cronolog.cc:86
STL namespace.
static bool mkdirs(const String &dirname)
Creates a directory (with all parent directories, if required)
Definition: FileUtils.cc:366
mutex m_mutex
Mutex for serializing access to member variables
Definition: Cronolog.h:105
Declarations for Cronolog.
File system utility functions.
int m_fd
Log file descriptor.
Definition: Cronolog.h:120
Logging routines and macros.
Compatibility Macros for C/C++.
Hypertable definitions
#define HT_FATALF(msg,...)
Definition: Logger.h:343
void write(time_t now, const string &line)
Writes a log line.
Definition: Cronolog.cc:67
string m_archive_dir
Directory containing log archives.
Definition: Cronolog.h:114
A String class based on std::string.
time_t m_roll_time
Time (seconds since Epoch) when next roll is required.
Definition: Cronolog.h:117
Cronolog(const string &name, const string &current_dir, const string &archive_dir)
Constructor.
Definition: Cronolog.cc:51