77
static FilePath GenericLogFile {
78
get { return "MonoDevelop.log"; }
81
static string FormattedGenericLogFile (int value)
83
return string.Format ("MonoDevelop-{0}.log", value);
86
static string FormattedUniqueFileName (DateTime timestamp)
88
return string.Format ("MonoDevelop.{0}.log", timestamp.ToString ("yyyy-MM-dd__HH-mm-ss"));
91
public static void Initialize (bool redirectOutput)
95
if (Platform.IsWindows || redirectOutput)
96
RedirectOutputToLogFile ();
99
static void PurgeOldLogs ()
101
// Delete all logs older than 30 days
102
if (!Directory.Exists (UserProfile.Current.LogDir))
105
var files = Directory.EnumerateFiles (UserProfile.Current.LogDir, "MonoDevelop.*.log")
106
.Select (f => new FileInfo (f))
107
.Where (f => f.CreationTimeUtc < DateTime.UtcNow.Subtract (TimeSpan.FromDays (30)));
109
foreach (var v in files)
113
static void RedirectOutputToLogFile ()
115
FilePath logDir = UserProfile.Current.LogDir;
116
if (!Directory.Exists (logDir))
117
Directory.CreateDirectory (logDir);
120
if (Platform.IsWindows) {
121
//TODO: redirect the file descriptors on Windows, just plugging in a textwriter won't get everything
122
RedirectOutputToFileWindows (logDir);
124
RedirectOutputToFileUnix (logDir);
130
static IEnumerable<string> GetGenericLogFiles (FilePath logDirectory)
132
// Look for MonoDevelop.log and also MonoDevelop-XXX.log and move them to MonoDevelop.{timestamp}.log files
133
// as we cannot symlink on windows and we want 'MonoDevelop.log' to be the newest log file
134
string additonalGenericLogs = Path.GetFileNameWithoutExtension (GenericLogFile) + "-";
135
return Directory.GetFiles (logDirectory)
136
.Where (f => f == GenericLogFile || f.StartsWith (additonalGenericLogs))
140
static void RedirectOutputToFileWindows (FilePath logDirectory)
142
// First try to move any generic MonoDevelop.log files to a timestamped filename
143
foreach (var path in GetGenericLogFiles (logDirectory)) {
145
var creationTime = File.GetCreationTime (path);
146
var destination = logDirectory.Combine (FormattedUniqueFileName (creationTime));
147
File.Copy (path, destination, true);
152
// Find the first free filename, try MonoDevelop.log first and then MonoDevelop-{0}.log
154
var newLogFileName = GenericLogFile;
155
var existingFiles = GetGenericLogFiles (logDirectory).Select (f => Path.GetFileName (f)).ToList ();
156
while (existingFiles.Contains (newLogFileName))
157
newLogFileName = FormattedGenericLogFile (count ++);
159
var logFile = new StreamWriter (logDirectory.Combine (newLogFileName));
160
logFile.AutoFlush = true;
161
Console.SetOut (logFile);
162
Console.SetError (logFile);
165
static void RedirectOutputToFileUnix (FilePath logDirectory)
167
const int STDOUT_FILENO = 1;
168
const int STDERR_FILENO = 2;
170
Mono.Unix.Native.OpenFlags flags = Mono.Unix.Native.OpenFlags.O_WRONLY
171
| Mono.Unix.Native.OpenFlags.O_CREAT | Mono.Unix.Native.OpenFlags.O_TRUNC;
172
var mode = Mono.Unix.Native.FilePermissions.S_IFREG
173
| Mono.Unix.Native.FilePermissions.S_IRUSR | Mono.Unix.Native.FilePermissions.S_IWUSR
174
| Mono.Unix.Native.FilePermissions.S_IRGRP | Mono.Unix.Native.FilePermissions.S_IWGRP;
176
var file = logDirectory.Combine (FormattedUniqueFileName (DateTime.Now));
177
int fd = Mono.Unix.Native.Syscall.open (file, flags, mode);
182
int res = Mono.Unix.Native.Syscall.dup2 (fd, STDOUT_FILENO);
187
res = Mono.Unix.Native.Syscall.dup2 (fd, STDERR_FILENO);
192
var genericLog = logDirectory.Combine (GenericLogFile);
193
File.Delete (genericLog);
194
Mono.Unix.Native.Syscall.symlink (file, genericLog);
196
Mono.Unix.Native.Syscall.close (fd);
75
200
internal static RemoteLogger RemoteLogger {