• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

logcat.cc

Go to the documentation of this file.
00001 /** @file
00002 
00003   Contains main function definition for logcat
00004 
00005   @section license License
00006 
00007   Licensed to the Apache Software Foundation (ASF) under one
00008   or more contributor license agreements.  See the NOTICE file
00009   distributed with this work for additional information
00010   regarding copyright ownership.  The ASF licenses this file
00011   to you under the Apache License, Version 2.0 (the
00012   "License"); you may not use this file except in compliance
00013   with the License.  You may obtain a copy of the License at
00014 
00015       http://www.apache.org/licenses/LICENSE-2.0
00016 
00017   Unless required by applicable law or agreed to in writing, software
00018   distributed under the License is distributed on an "AS IS" BASIS,
00019   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00020   See the License for the specific language governing permissions and
00021   limitations under the License.
00022  */
00023 #include "ink_config.h"
00024 #include "ink_file.h"
00025 #include "I_Layout.h"
00026 #include "I_Version.h"
00027 
00028 #define PROGRAM_NAME        "traffic_logcat"
00029 #define MAX_LOGBUFFER_SIZE  65536
00030 
00031 #include <poll.h>
00032 
00033 #include "LogStandalone.cc"
00034 
00035 #include "LogAccess.h"
00036 #include "LogField.h"
00037 #include "LogFilter.h"
00038 #include "LogFormat.h"
00039 #include "LogFile.h"
00040 #include "LogHost.h"
00041 #include "LogObject.h"
00042 #include "LogConfig.h"
00043 #include "LogBuffer.h"
00044 #include "LogUtils.h"
00045 #include "LogSock.h"
00046 #include "LogPredefined.h"
00047 #include "Log.h"
00048 
00049 // logcat-specific command-line flags
00050 static int version_flag = 0;
00051 static int help = 0;
00052 static int squid_flag = 0;
00053 static int follow_flag = 0;
00054 static int clf_flag = 0;
00055 static int elf_flag = 0;
00056 static int elf2_flag = 0;
00057 static int auto_filenames = 0;
00058 static int overwrite_existing_file = 0;
00059 static char output_file[1024];
00060 int auto_clear_cache_flag = 0;
00061 
00062 static const ArgumentDescription argument_descriptions[] = {
00063 
00064   {"output_file", 'o', "Specify output file", "S1023", &output_file, NULL, NULL},
00065   {"auto_filenames", 'a', "Automatically generate output names",
00066    "T", &auto_filenames, NULL, NULL},
00067   {"follow", 'f', "Follow the log file as it grows", "T", &follow_flag, NULL, NULL},
00068   {"clf", 'C', "Convert to Common Logging Format", "T", &clf_flag, NULL, NULL},
00069   {"elf", 'E', "Convert to Extended Logging Format", "T", &elf_flag, NULL, NULL},
00070   {"help", 'h', "Give this help", "T", &help, NULL, NULL},
00071   {"squid", 'S', "Convert to Squid Logging Format", "T", &squid_flag, NULL, NULL},
00072   {"debug_tags", 'T', "Colon-Separated Debug Tags", "S1023", error_tags, NULL, NULL},
00073   {"version", 'V', "Print Version Id", "T", &version_flag, NULL, NULL},
00074   {"overwrite_output", 'w', "Overwrite existing output file(s)", "T",
00075    &overwrite_existing_file, NULL, NULL},
00076   {"elf2", '2', "Convert to Extended2 Logging Format", "T", &elf2_flag, NULL,
00077    NULL}
00078 };
00079 
00080 static const char *USAGE_LINE = "Usage: " PROGRAM_NAME " [-o output-file | -a] [-CEhS"
00081 #ifdef DEBUG
00082   "T"
00083 #endif
00084   "Vw2] [input-file ...]";
00085 
00086 
00087 
00088 static int
00089 process_file(int in_fd, int out_fd)
00090 {
00091   char buffer[MAX_LOGBUFFER_SIZE];
00092   int nread, buffer_bytes;
00093   unsigned bytes = 0;
00094 
00095   while (true) {
00096     // read the next buffer from file descriptor
00097     //
00098     Debug("logcat", "Reading buffer ...");
00099     memset(buffer, 0, sizeof(buffer));
00100 
00101     // read the first 8 bytes of the header, which will give us the
00102     // cookie and the version number.
00103     //
00104     unsigned first_read_size = sizeof(uint32_t) + sizeof(uint32_t);
00105     unsigned header_size = sizeof(LogBufferHeader);
00106     LogBufferHeader *header = (LogBufferHeader *) & buffer[0];
00107 
00108     nread = read(in_fd, buffer, first_read_size);
00109     if (!nread || nread == EOF)
00110       return 0;
00111 
00112     // ensure that this is a valid logbuffer header
00113     //
00114     if (header->cookie != LOG_SEGMENT_COOKIE) {
00115       fprintf(stderr, "Bad LogBuffer!\n");
00116       return 1;
00117     }
00118     // read the rest of the header
00119     //
00120     unsigned second_read_size = header_size - first_read_size;
00121 
00122     nread = read(in_fd, &buffer[first_read_size], second_read_size);
00123     if (!nread || nread == EOF) {
00124       if (follow_flag)
00125         return 0;
00126 
00127       fprintf(stderr, "Bad LogBufferHeader read!\n");
00128       return 1;
00129     }
00130     // read the rest of the buffer
00131     //
00132     uint32_t byte_count = header->byte_count;
00133 
00134     if (byte_count > sizeof(buffer)) {
00135       fprintf(stderr, "Buffer too large!\n");
00136       return 1;
00137     }
00138     buffer_bytes = byte_count - header_size;
00139     if (buffer_bytes == 0)
00140       return 0;
00141     if (buffer_bytes < 0) {
00142       fprintf(stderr, "No buffer body!\n");
00143       return 1;
00144     }
00145     // Read the next full buffer (allowing for "partial" reads)
00146     nread = 0;
00147     while (nread < buffer_bytes) {
00148       int rc = read(in_fd, &buffer[header_size] + nread, buffer_bytes - nread);
00149 
00150       if ((rc == EOF) && (!follow_flag)) {
00151         fprintf(stderr, "Bad LogBuffer read!\n");
00152         return 1;
00153       }
00154 
00155       if (rc > 0)
00156         nread += rc;
00157     }
00158 
00159     if (nread > buffer_bytes) {
00160       fprintf(stderr, "Read too many bytes!\n");
00161       return 1;
00162     }
00163     // see if there is an alternate format request from the command
00164     // line
00165     //
00166     const char * alt_format = NULL;
00167     if (squid_flag)
00168       alt_format = PreDefinedFormatInfo::squid;
00169     if (clf_flag)
00170       alt_format = PreDefinedFormatInfo::common;
00171     if (elf_flag)
00172       alt_format = PreDefinedFormatInfo::extended;
00173     if (elf2_flag)
00174       alt_format = PreDefinedFormatInfo::extended2;
00175 
00176     // convert the buffer to ascii entries and place onto stdout
00177     //
00178     if (header->fmt_fieldlist()) {
00179       bytes += LogFile::write_ascii_logbuffer(header, out_fd, ".", alt_format);
00180     } else {
00181       // TODO investigate why this buffer goes wonky
00182     }
00183   }
00184 }
00185 
00186 static int
00187 open_output_file(char *output_file)
00188 {
00189   int file_desc = 0;
00190 
00191   if (!overwrite_existing_file) {
00192     if (access(output_file, F_OK)) {
00193       if (errno != ENOENT) {
00194         fprintf(stderr, "Error accessing output file %s: ", output_file);
00195         perror(0);
00196         file_desc = -1;
00197       }
00198     } else {
00199       fprintf(stderr, "Error, output file %s already exists.\n" "Select a different filename or use the -w flag\n",
00200               output_file);
00201       file_desc = -1;
00202     }
00203   }
00204 
00205   if (file_desc == 0) {
00206     file_desc = open(output_file, O_WRONLY | O_TRUNC | O_CREAT, 0640);
00207 
00208     if (file_desc < 0) {
00209       fprintf(stderr, "Error while opening output file %s: ", output_file);
00210       perror(0);
00211     }
00212   }
00213 
00214   return file_desc;
00215 }
00216 
00217 
00218 /*-------------------------------------------------------------------------
00219   main
00220   -------------------------------------------------------------------------*/
00221 
00222 int
00223 main(int /* argc ATS_UNUSED */, char *argv[])
00224 {
00225   enum
00226   {
00227     NO_ERROR = 0,
00228     CMD_LINE_OPTION_ERROR = 1,
00229     DATA_PROCESSING_ERROR = 2
00230   };
00231 
00232   // build the application information structure
00233   //
00234   appVersionInfo.setup(PACKAGE_NAME,PROGRAM_NAME, PACKAGE_VERSION, __DATE__,
00235                        __TIME__, BUILD_MACHINE, BUILD_PERSON, "");
00236 
00237   // Before accessing file system initialize Layout engine
00238   Layout::create();
00239   // process command-line arguments
00240   //
00241   output_file[0] = 0;
00242   process_args(argument_descriptions, countof(argument_descriptions), argv, USAGE_LINE);
00243 
00244   // check for the version number request
00245   //
00246   if (version_flag) {
00247     fprintf(stderr, "%s\n", appVersionInfo.FullVersionInfoStr);
00248     _exit(NO_ERROR);
00249   }
00250   // check for help request
00251   //
00252   if (help) {
00253     usage(argument_descriptions, countof(argument_descriptions), USAGE_LINE);
00254     _exit(NO_ERROR);
00255   }
00256   // check that only one of the -o and -a options was specified
00257   //
00258   if (output_file[0] != 0 && auto_filenames) {
00259     fprintf(stderr, "Error: specify only one of -o <file> and -a\n");
00260     _exit(CMD_LINE_OPTION_ERROR);
00261   }
00262   // initialize this application for standalone logging operation
00263   //
00264   init_log_standalone_basic(PROGRAM_NAME);
00265 
00266   Log::init(Log::NO_REMOTE_MANAGEMENT | Log::LOGCAT);
00267 
00268   // setup output file
00269   //
00270   int out_fd = STDOUT_FILENO;
00271   if (output_file[0] != 0) {
00272     out_fd = open_output_file(output_file);
00273 
00274     if (out_fd < 0) {
00275       _exit(DATA_PROCESSING_ERROR);
00276     }
00277   } else if (!auto_filenames) {
00278     out_fd = STDOUT_FILENO;
00279   }
00280   // process file arguments
00281   //
00282   int error = NO_ERROR;
00283 
00284   if (n_file_arguments) {
00285     int bin_ext_len = strlen(LOG_FILE_BINARY_OBJECT_FILENAME_EXTENSION);
00286     int ascii_ext_len = strlen(LOG_FILE_ASCII_OBJECT_FILENAME_EXTENSION);
00287 
00288     for (unsigned i = 0; i < n_file_arguments; ++i) {
00289       int in_fd = open(file_arguments[i], O_RDONLY);
00290       if (in_fd < 0) {
00291         fprintf(stderr, "Error opening input file %s: ", file_arguments[i]);
00292         perror(0);
00293         error = DATA_PROCESSING_ERROR;
00294       } else {
00295 #if HAVE_POSIX_FADVISE
00296         posix_fadvise(in_fd, 0, 0, POSIX_FADV_DONTNEED);
00297 #endif
00298         if (auto_filenames) {
00299           // change .blog to .log
00300           //
00301           int n = strlen(file_arguments[i]);
00302           int copy_len = (n >= bin_ext_len ? (strcmp(&file_arguments[i][n - bin_ext_len],
00303                                                      LOG_FILE_BINARY_OBJECT_FILENAME_EXTENSION) ==
00304                                               0 ? n - bin_ext_len : n) : n);
00305 
00306           char *out_filename = (char *)ats_malloc(copy_len + ascii_ext_len + 1);
00307 
00308           memcpy(out_filename, file_arguments[i], copy_len);
00309           memcpy(&out_filename[copy_len], LOG_FILE_ASCII_OBJECT_FILENAME_EXTENSION, ascii_ext_len);
00310           out_filename[copy_len + ascii_ext_len] = 0;
00311 
00312           out_fd = open_output_file(out_filename);
00313           ats_free(out_filename);
00314 
00315           if (out_fd < 0) {
00316             error = DATA_PROCESSING_ERROR;
00317             continue;
00318           }
00319         }
00320         if (follow_flag)
00321           lseek(in_fd, 0, SEEK_END);
00322 
00323         while (true) {
00324           if (process_file(in_fd, out_fd) != 0) {
00325             error = DATA_PROCESSING_ERROR;
00326             break;
00327           }
00328           if (!follow_flag)
00329             break;
00330           else
00331             usleep(10000);      // This avoids burning CPU, using poll() would have been nice, but doesn't work I think.
00332         }
00333       }
00334     }
00335   } else {
00336     // read from stdin, allow STDIN to go EOF a few times until we get synced
00337     //
00338     int tries = 3;
00339     while (--tries >= 0) {
00340       if (process_file(STDIN_FILENO, out_fd) != 0)
00341         tries = -1;
00342     }
00343   }
00344 
00345   _exit(error);
00346 }

Generated by  doxygen 1.7.1