1 /* -------------------------------------------------------------------------- *
2  *                          OpenSim:  LogManager.cpp                          *
3  * -------------------------------------------------------------------------- *
4  * The OpenSim API is a toolkit for musculoskeletal modeling and simulation.  *
5  * See http://opensim.stanford.edu and the NOTICE file for more information.  *
6  * OpenSim is developed at Stanford University and supported by the US        *
7  * National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA    *
8  * through the Warrior Web program.                                           *
9  *                                                                            *
10  * Copyright (c) 2005-2017 Stanford University and the Authors                *
11  *                                                                            *
12  * Licensed under the Apache License, Version 2.0 (the "License"); you may    *
13  * not use this file except in compliance with the License. You may obtain a  *
14  * copy of the License at http://www.apache.org/licenses/LICENSE-2.0.         *
15  *                                                                            *
16  * Unless required by applicable law or agreed to in writing, software        *
17  * distributed under the License is distributed on an "AS IS" BASIS,          *
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
19  * See the License for the specific language governing permissions and        *
20  * limitations under the License.                                             *
21  * -------------------------------------------------------------------------- */
22 #include "LogManager.h"
23 #include <fstream>
24 
25 using namespace OpenSim;
26 
27 // Initialize static members
28 LogBuffer LogManager::out;
29 LogBuffer LogManager::err;
30 std::ostream LogManager::cout(std::cout.rdbuf()); // This cout writes to the actual standard out
31 std::ostream LogManager::cerr(std::cerr.rdbuf()); // This cerr writes to the actual standard error
32 
33 // Initialize a static log manager to force the constructor to be called
34 LogManager logManager;
35 
36 //=============================================================================
37 // FileLogCallback
38 //=============================================================================
StreamLogCallback(const std::string & filename)39 StreamLogCallback::StreamLogCallback(const std::string &filename)
40     : _out(new std::ofstream(filename.c_str())), _ownsStream(true)
41 {}
42 
StreamLogCallback(std::ostream * aOut,bool aOwnsStream)43 StreamLogCallback::StreamLogCallback(std::ostream *aOut, bool aOwnsStream)
44     : _out(aOut), _ownsStream(aOwnsStream)
45 {}
46 
~StreamLogCallback()47 StreamLogCallback::~StreamLogCallback()
48 {
49     if(_ownsStream) delete _out;
50 }
51 
log(const std::string & str)52 void StreamLogCallback::log(const std::string &str)
53 {
54     *_out << str << std::flush;
55 }
56 
57 //=============================================================================
58 // LogBuffer
59 //=============================================================================
LogBuffer()60 LogBuffer::LogBuffer()
61 {
62 }
63 
~LogBuffer()64 LogBuffer::~LogBuffer()
65 {
66     for(int i = 0; i < _logCallbacks.size(); i++) {
67         delete _logCallbacks[i];
68     }
69 }
70 
71 // Assumes caller owns this output stream (will never be deleted)
72 bool LogBuffer::
addLogCallback(LogCallback * aLogCallback)73 addLogCallback(LogCallback *aLogCallback)
74 {
75     if(_logCallbacks.findIndex(aLogCallback) >= 0) return false;
76     _logCallbacks.append(aLogCallback);
77     return true;
78 }
79 
80 bool LogBuffer::
removeLogCallback(LogCallback * aLogCallback)81 removeLogCallback(LogCallback *aLogCallback)
82 {
83     int index = _logCallbacks.findIndex(aLogCallback);
84     if(index < 0) return false;
85     _logCallbacks.remove(index);
86     return true;
87 }
88 
89 int LogBuffer::
sync()90 sync()
91 {
92     // Pass current string to all log callbacks
93     for(int i=0; i<_logCallbacks.getSize(); i++) _logCallbacks[i]->log(str());
94     // Reset current buffer contents
95     str("");
96     return std::stringbuf::sync();
97 }
98 
99 //=============================================================================
100 // LogManager
101 //=============================================================================
LogManager()102 LogManager::LogManager()
103 {
104     // Seems to be causing crashes in the GUI... maybe a multithreading issue.
105 
106     // Change the underlying streambuf for the standard cout/cerr to our custom buffers
107     std::cout.rdbuf(&out);
108     std::cerr.rdbuf(&err);
109 
110     // Redirect output to the terminal
111     out.addLogCallback(new StreamLogCallback(&cout,false));
112     err.addLogCallback(new StreamLogCallback(&cerr,false));
113 
114     // Optional: Redirect output to file
115 #if OPENSIM_LOG_TO_FILE
116     out.addLogCallback(new StreamLogCallback("out.log"));
117     err.addLogCallback(new StreamLogCallback("err.log"));
118 #endif
119 }
120 
~LogManager()121 LogManager::~LogManager()
122 {
123     std::cout << std::flush;
124     std::cerr << std::flush;
125 }
126 
getInstance()127 LogManager *LogManager::getInstance()
128 {
129     return &logManager;
130 }
131 
getOutBuffer()132 LogBuffer *LogManager::getOutBuffer()
133 {
134     return &out;
135 }
136 
getErrBuffer()137 LogBuffer *LogManager::getErrBuffer()
138 {
139     return &err;
140 }
141