1 // -*- mode:c++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * ceph - scalable distributed file system
6 * copyright (c) 2014 john spray <john.spray@inktank.com>
8 * this is free software; you can redistribute it and/or
9 * modify it under the terms of the gnu lesser general public
10 * license version 2.1, as published by the free software
11 * foundation. see file copying.
15 #include "JournalFilter.h"
17 #include "common/ceph_argparse.h"
19 #include "mds/events/ESession.h"
20 #include "mds/events/EUpdate.h"
22 #define dout_context g_ceph_context
23 #define dout_subsys ceph_subsys_mds
26 const string JournalFilter::range_separator("..");
30 * Return whether a LogEvent is to be included or excluded.
32 * The filter parameters are applied on an AND basis: if any
33 * condition is not met, the event is excluded. Try to do
34 * the fastest checks first.
36 bool JournalFilter::apply(uint64_t pos, LogEvent &le) const
38 /* Filtering by journal offset range */
39 if (pos < range_start || pos >= range_end) {
43 /* Filtering by event type */
44 if (event_type != 0) {
45 if (le.get_type() != event_type) {
50 /* Filtering by client */
51 if (client_name.num()) {
52 EMetaBlob const *metablob = le.get_metablob();
54 if (metablob->get_client_name() != client_name) {
57 } else if (le.get_type() == EVENT_SESSION) {
58 ESession *es = reinterpret_cast<ESession*>(&le);
59 if (es->get_client_inst().name != client_name) {
67 /* Filtering by inode */
69 EMetaBlob const *metablob = le.get_metablob();
71 std::set<inodeno_t> inodes;
72 metablob->get_inodes(inodes);
73 bool match_any = false;
74 for (std::set<inodeno_t>::iterator i = inodes.begin(); i != inodes.end(); ++i) {
88 /* Filtering by frag and dentry */
89 if (!frag_dentry.empty() || frag.ino) {
90 EMetaBlob const *metablob = le.get_metablob();
92 std::map<dirfrag_t, std::set<std::string> > dentries;
93 metablob->get_dentries(dentries);
96 bool match_any = false;
97 for (std::map<dirfrag_t, std::set<std::string> >::iterator i = dentries.begin();
98 i != dentries.end(); ++i) {
99 if (i->first == frag) {
109 if (!frag_dentry.empty()) {
110 bool match_any = false;
111 for (std::map<dirfrag_t, std::set<std::string> >::iterator i = dentries.begin();
112 i != dentries.end() && !match_any; ++i) {
113 std::set<std::string> const &names = i->second;
114 for (std::set<std::string>::iterator j = names.begin();
115 j != names.end() && !match_any; ++j) {
116 if (*j == frag_dentry) {
131 /* Filtering by file path */
132 if (!path_expr.empty()) {
133 EMetaBlob const *metablob = le.get_metablob();
135 std::vector<std::string> paths;
136 metablob->get_paths(paths);
137 bool match_any = false;
138 for (std::vector<std::string>::iterator p = paths.begin(); p != paths.end(); ++p) {
139 if ((*p).find(path_expr) != std::string::npos) {
156 int JournalFilter::parse_args(
157 std::vector<const char*> &argv,
158 std::vector<const char*>::iterator &arg)
160 while(arg != argv.end()) {
162 if (ceph_argparse_witharg(argv, arg, &arg_str, "--range", (char*)NULL)) {
163 size_t sep_loc = arg_str.find(JournalFilter::range_separator);
164 if (sep_loc == std::string::npos || arg_str.size() <= JournalFilter::range_separator.size()) {
165 derr << "Invalid range '" << arg_str << "'" << dendl;
169 // We have a lower bound
171 std::string range_start_str = arg_str.substr(0, sep_loc);
172 std::string parse_err;
173 range_start = strict_strtoll(range_start_str.c_str(), 0, &parse_err);
174 if (!parse_err.empty()) {
175 derr << "Invalid lower bound '" << range_start_str << "': " << parse_err << dendl;
180 if (sep_loc < arg_str.size() - JournalFilter::range_separator.size()) {
181 std::string range_end_str = arg_str.substr(sep_loc + range_separator.size());
182 std::string parse_err;
183 range_end = strict_strtoll(range_end_str.c_str(), 0, &parse_err);
184 if (!parse_err.empty()) {
185 derr << "Invalid upper bound '" << range_end_str << "': " << parse_err << dendl;
189 } else if (ceph_argparse_witharg(argv, arg, &arg_str, "--path", (char*)NULL)) {
190 dout(4) << "Filtering by path '" << arg_str << "'" << dendl;
192 } else if (ceph_argparse_witharg(argv, arg, &arg_str, "--inode", (char*)NULL)) {
193 dout(4) << "Filtering by inode '" << arg_str << "'" << dendl;
194 std::string parse_err;
195 inode = strict_strtoll(arg_str.c_str(), 0, &parse_err);
196 if (!parse_err.empty()) {
197 derr << "Invalid inode '" << arg_str << "': " << parse_err << dendl;
200 } else if (ceph_argparse_witharg(argv, arg, &arg_str, "--type", (char*)NULL)) {
201 std::string parse_err;
202 event_type = LogEvent::str_to_type(arg_str);
203 if (event_type == LogEvent::EventType(-1)) {
204 derr << "Invalid event type '" << arg_str << "': " << parse_err << dendl;
208 } else if (ceph_argparse_witharg(argv, arg, &arg_str, "--frag", (char*)NULL)) {
209 std::string const frag_sep = ".";
210 size_t sep_loc = arg_str.find(frag_sep);
211 std::string inode_str;
212 std::string frag_str;
213 if (sep_loc != std::string::npos) {
214 inode_str = arg_str.substr(0, sep_loc);
215 frag_str = arg_str.substr(sep_loc + 1);
221 std::string parse_err;
222 inodeno_t frag_ino = strict_strtoll(inode_str.c_str(), 0, &parse_err);
223 if (!parse_err.empty()) {
224 derr << "Invalid inode '" << inode_str << "': " << parse_err << dendl;
228 uint32_t frag_enc = strict_strtoll(frag_str.c_str(), 0, &parse_err);
229 if (!parse_err.empty()) {
230 derr << "Invalid frag '" << frag_str << "': " << parse_err << dendl;
234 frag = dirfrag_t(frag_ino, frag_t(frag_enc));
235 dout(4) << "dirfrag filter: '" << frag << "'" << dendl;
236 } else if (ceph_argparse_witharg(argv, arg, &arg_str, "--dname", (char*)NULL)) {
237 frag_dentry = arg_str;
238 dout(4) << "dentry filter: '" << frag_dentry << "'" << dendl;
239 } else if (ceph_argparse_witharg(argv, arg, &arg_str, "--client", (char*)NULL)) {
240 std::string parse_err;
241 int64_t client_num = strict_strtoll(arg_str.c_str(), 0, &parse_err);
242 if (!parse_err.empty()) {
243 derr << "Invalid client number " << arg_str << dendl;
246 client_name = entity_name_t::CLIENT(client_num);
248 // We're done with args the filter understands
257 * If the filter params are only range, then return
258 * true and set start & end. Else return false.
260 * Use this to discover if the user has requested a contiguous range
261 * rather than any per-event filtering.
263 bool JournalFilter::get_range(uint64_t &start, uint64_t &end) const
265 if (!path_expr.empty()
269 || client_name.num() != 0
270 || (range_start == 0 && range_end == (uint64_t)(-1))) {