Coverage for /Syzygy/trace/service/service_main.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
59.4%631060.C++source

Line-by-line coverage:

   1    :  // Copyright 2012 Google Inc.
   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 implied.
  12    :  // See the License for the specific language governing permissions and
  13    :  // limitations under the License.
  14    :  
  15    :  #include <iostream>
  16    :  
  17    :  #include "base/at_exit.h"
  18    :  #include "base/command_line.h"
  19    :  #include "base/environment.h"
  20    :  #include "base/file_path.h"
  21    :  #include "base/logging.h"
  22    :  #include "base/string_number_conversions.h"
  23    :  #include "base/string_piece.h"
  24    :  #include "base/string_util.h"
  25    :  #include "base/utf_string_conversions.h"
  26    :  #include "base/memory/scoped_ptr.h"
  27    :  #include "base/threading/thread.h"
  28    :  #include "sawbuck/common/com_utils.h"
  29    :  #include "syzygy/trace/protocol/call_trace_defs.h"
  30    :  #include "syzygy/trace/rpc/rpc_helpers.h"
  31    :  #include "syzygy/trace/service/service.h"
  32    :  #include "syzygy/trace/service/service_rpc_impl.h"
  33    :  #include "syzygy/trace/service/trace_file_writer_factory.h"
  34    :  
  35    :  namespace trace {
  36    :  namespace service {
  37    :  namespace {
  38    :  
  39    :  using ::trace::client::CreateRpcBinding;
  40    :  using ::trace::client::InvokeRpc;
  41    :  
  42    :  // Minimum buffer size to allow (1 MB).
  43    :  const int kMinBufferSize = 1024 * 1024;
  44    :  
  45    :  // Minumum number of buffers to allocate.
  46    :  const int kMinBuffers = 16;
  47    :  
  48    :  // A static location to which the current instance id can be saved. We
  49    :  // persist it here so that OnConsoleCtrl can have access to the instance
  50    :  // id when it is invoked on the signal handler thread.
  51    :  wchar_t saved_instance_id[16] = {0};
  52    :  
  53    :  // Forward declaration.
  54    :  bool StopService(const base::StringPiece16& instance_id);
  55    :  
  56    :  // Handler function to be called on exit signals (Ctrl-C, TERM, etc...).
  57  i :  BOOL WINAPI OnConsoleCtrl(DWORD ctrl_type) {
  58  i :    if (ctrl_type != CTRL_LOGOFF_EVENT) {
  59  i :      StopService(saved_instance_id);
  60  i :      return TRUE;
  61    :    }
  62  i :    return FALSE;
  63  i :  }
  64    :  
  65    :  const char* const kInstanceId = "instance-id";
  66    :  
  67    :  const char kUsage[] =
  68    :      "Usage: call_trace_service ACTION [OPTIONS]\n"
  69    :      "\n"
  70    :      "Actions:\n"
  71    :      "  start              Start the call trace service.\n"
  72    :      "  stop               Stop the call trace service.\n"
  73    :      "\n"
  74    :      "Options:\n"
  75    :      "  --help             Show this help message.\n"
  76    :      "  --trace-dir=PATH   The directory in which to write the trace files.\n"
  77    :      "  --buffer-size=NUM  The size (in bytes) of each buffer to allocate.\n"
  78    :      "  --num-incremental-buffers=NUM\n"
  79    :      "                     The number of buffers by which to grow the buffer\n"
  80    :      "                     pool each time the client exhausts its available\n"
  81    :      "                     buffer space.\n"
  82    :      "  --enable-exits     Enable exit tracing (off by default).\n"
  83    :      "  --verbose          Increase the logging verbosity to also include\n"
  84    :      "                     debug-level information.\n"
  85    :      "  --instance-id=ID   A unique identifier to use for the RPC endoint.\n"
  86    :      "                     This allows multiple instances of the service to\n"
  87    :      "                     run concurently. By default, this will be the value\n"
  88    :      "                     of the SYZYGY_RPC_INSTANCE_ID environment variable,\n"
  89    :      "                     or empty.\n"
  90    :      "\n";
  91    :  
  92  i :  int Usage() {
  93  i :    std::cout << kUsage;
  94  i :    return 1;
  95  i :  }
  96    :  
  97  E :  bool GetInstanceId(const CommandLine* cmd_line, std::wstring* id) {
  98  E :    DCHECK(cmd_line != NULL);
  99  E :    DCHECK(id != NULL);
 100    :  
 101  E :    *id = cmd_line->GetSwitchValueNative(kInstanceId);
 102  E :    if (id->empty()) {
 103  i :      scoped_ptr<base::Environment> env(base::Environment::Create());
 104  i :      CHECK(env.get() != NULL);
 105  i :      std::string value;
 106  i :      env->GetVar(::kSyzygyRpcInstanceIdEnvVar, &value);
 107  i :      *id = ::UTF8ToWide(value);
 108  i :    }
 109    :  
 110  E :    const size_t kMaxLength = arraysize(saved_instance_id) - 1;
 111  E :    if (id->length() > kMaxLength) {
 112  i :      LOG(ERROR) << "The instance id '" << *id << "' is too long. "
 113    :                 << "The max length is " << kMaxLength << " characters.";
 114  i :      return false;
 115    :    }
 116    :  
 117  E :    return true;
 118  E :  }
 119    :  
 120  E :  bool RunService(const CommandLine* cmd_line) {
 121  E :    DCHECK(cmd_line != NULL);
 122    :  
 123  E :    base::Thread writer_thread("trace-file-writer");
 124    :    if (!writer_thread.StartWithOptions(
 125  E :            base::Thread::Options(MessageLoop::TYPE_IO, 0))) {
 126  i :      LOG(ERROR) << "Failed to start call trace service writer thread.";
 127  i :      return 1;
 128    :    }
 129    :  
 130  E :    MessageLoop* message_loop = writer_thread.message_loop();
 131  E :    TraceFileWriterFactory trace_file_writer_factory(message_loop);
 132  E :    Service call_trace_service(&trace_file_writer_factory);
 133  E :    RpcServiceInstanceManager rpc_instance(&call_trace_service);
 134    :  
 135    :    // Get/set the instance id.
 136  E :    std::wstring instance_id;
 137  E :    if (!GetInstanceId(cmd_line, &instance_id))
 138  i :      return false;
 139    :  
 140  E :    call_trace_service.set_instance_id(instance_id);
 141    :    base::wcslcpy(saved_instance_id,
 142    :                  instance_id.c_str(),
 143  E :                  arraysize(saved_instance_id));
 144    :  
 145    :    // Set up the trace directory.
 146  E :    FilePath trace_directory(cmd_line->GetSwitchValuePath("trace-dir"));
 147  E :    if (trace_directory.empty())
 148  E :      trace_directory = FilePath(L".");
 149  E :    if (!trace_file_writer_factory.SetTraceFileDirectory(trace_directory))
 150  i :      return false;
 151    :  
 152    :    // Setup the buffer size.
 153  E :    std::wstring buffer_size_str(cmd_line->GetSwitchValueNative("buffer-size"));
 154  E :    if (!buffer_size_str.empty()) {
 155  i :      int num = 0;
 156  i :      if (!base::StringToInt(buffer_size_str, &num) || num < kMinBufferSize) {
 157  i :        LOG(ERROR) << "Buffer size is too small (<" << kMinBufferSize << ").";
 158  i :        return false;
 159    :      }
 160  i :      call_trace_service.set_buffer_size_in_bytes(num);
 161    :    }
 162    :  
 163  E :    if (cmd_line->HasSwitch("enable-exits")) {
 164  i :      call_trace_service.set_flags(TRACE_FLAG_ENTER | TRACE_FLAG_EXIT);
 165    :    }
 166    :  
 167    :    // Setup the number of incremental buffers
 168    :    std::wstring buffers_str(
 169  E :        cmd_line->GetSwitchValueNative("num-incremental-buffers"));
 170  E :    if (!buffers_str.empty()) {
 171  i :      int num = 0;
 172  i :      if (!base::StringToInt(buffers_str, &num) || num < kMinBuffers) {
 173  i :        LOG(ERROR) << "Number of incremental buffers is too small (<"
 174    :                   << kMinBuffers << ").";
 175  i :        return false;
 176    :      }
 177  i :      call_trace_service.set_num_incremental_buffers(num);
 178    :    }
 179    :  
 180    :    // Setup the handler for exit signals.
 181  E :    if (!SetConsoleCtrlHandler(&OnConsoleCtrl, TRUE)) {
 182  i :      DWORD error = ::GetLastError();
 183  i :      LOG(ERROR) << "Failed to register shutdown handler: "
 184    :                 << com::LogWe(error) << ".";
 185  i :      return false;
 186    :    }
 187    :  
 188    :    // Run the service in blocking mode. This will not return until the service
 189    :    // has been externally stopped.
 190  E :    call_trace_service.Start(false);
 191    :  
 192    :    // We no longer need to look out exit signals.
 193  E :    SetConsoleCtrlHandler(&OnConsoleCtrl, FALSE);
 194    :  
 195    :    // The call trace service will be stopped on destruction.
 196  E :    return true;
 197  E :  }
 198    :  
 199  E :  bool StopService(const base::StringPiece16& instance_id) {
 200  E :    std::wstring protocol;
 201  E :    std::wstring endpoint;
 202    :  
 203  E :    ::GetSyzygyCallTraceRpcProtocol(&protocol);
 204  E :    ::GetSyzygyCallTraceRpcEndpoint(instance_id, &endpoint);
 205    :  
 206  E :    LOG(INFO) << "Stopping call trace logging service instance at '"
 207    :              << endpoint << "' via " << protocol << '.';
 208    :  
 209  E :    handle_t binding = NULL;
 210  E :    if (!CreateRpcBinding(protocol, endpoint, &binding)) {
 211  i :      LOG(ERROR) << "Failed to connect to call trace logging service.";
 212  i :      return false;
 213    :    }
 214    :  
 215  E :    if (!InvokeRpc(CallTraceClient_Stop, binding).succeeded()) {
 216  i :      LOG(ERROR) << "Failed to stop call trace logging service.";
 217  i :      return false;
 218    :    }
 219    :  
 220    :    // TODO(rogerm): It would be nice to make this blocking until the
 221    :    //    service actually shuts down. Perhaps with retries on the stop
 222    :    //    request.
 223  E :    LOG(INFO) << "Call trace service shutdown has been requested.";
 224  E :    return true;
 225  E :  }
 226    :  
 227  E :  extern "C" int main(int argc, char** argv) {
 228  E :    base::AtExitManager at_exit_manager;
 229  E :    CommandLine::Init(argc, argv);
 230  E :    const int kVlogLevelVerbose = -2;
 231    :    if (!logging::InitLogging(
 232    :            L"",
 233    :            logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG,
 234    :            logging::DONT_LOCK_LOG_FILE,
 235    :            logging::APPEND_TO_OLD_LOG_FILE,
 236  E :            logging::ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS)) {
 237  i :      return 1;
 238    :    }
 239    :  
 240    :    // TODO(rogerm): Turn on ETW logging as well.
 241    :  
 242  E :    CommandLine* cmd_line = CommandLine::ForCurrentProcess();
 243  E :    DCHECK(cmd_line != NULL);
 244    :  
 245  E :    if (cmd_line->HasSwitch("verbose")) {
 246  E :      logging::SetMinLogLevel(kVlogLevelVerbose);
 247    :    }
 248    :  
 249  E :    if (cmd_line->HasSwitch("help") || cmd_line->GetArgs().size() < 1) {
 250  i :      return Usage();
 251    :    }
 252    :  
 253  E :    if (LowerCaseEqualsASCII(cmd_line->GetArgs()[0], "stop")) {
 254  E :      std::wstring id;
 255  E :      return (GetInstanceId(cmd_line, &id) && StopService(id)) ? 0 : 1;
 256    :    }
 257    :  
 258  E :    if (LowerCaseEqualsASCII(cmd_line->GetArgs()[0], "start")) {
 259  E :      return RunService(cmd_line) ? 0 : 1;
 260    :    }
 261    :  
 262  i :    return Usage();
 263  E :  }
 264    :  
 265    :  }  // namespace
 266    :  }  // namespace service
 267    :  }  // namespace trace

Coverage information generated Thu Sep 06 11:30:46 2012.