aboutsummaryrefslogtreecommitdiff
path: root/src/log.cpp
blob: 78fa32026f01f47149ac989e3dc3a79e3f469c83 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/*
Minetest-c55
Copyright (C) 2011 celeron55, Perttu Ahola <celeron55@gmail.com>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "log.h"

#include <map>
#include <list>
#include <sstream>
#include <algorithm>
#include "threads.h"
#include "debug.h"
#include "gettime.h"

std::list<ILogOutput*> log_outputs[LMT_NUM_VALUES];
std::map<threadid_t, std::string> log_threadnames;

void log_add_output(ILogOutput *out, enum LogMessageLevel lev)
{
	log_outputs[lev].push_back(out);
}

void log_add_output_maxlev(ILogOutput *out, enum LogMessageLevel lev)
{
	for(int i=0; i<=lev; i++)
		log_outputs[i].push_back(out);
}

void log_add_output_all_levs(ILogOutput *out)
{
	for(int i=0; i<LMT_NUM_VALUES; i++)
		log_outputs[i].push_back(out);
}

void log_remove_output(ILogOutput *out)
{
	for(int i=0; i<LMT_NUM_VALUES; i++){
		std::list<ILogOutput*>::iterator it =
				std::find(log_outputs[i].begin(), log_outputs[i].end(), out);
		if(it != log_outputs[i].end())
			log_outputs[i].erase(it);
	}
}

void log_register_thread(const std::string &name)
{
	threadid_t id = get_current_thread_id();
	log_threadnames[id] = name;
}

void log_deregister_thread()
{
	threadid_t id = get_current_thread_id();
	log_threadnames.erase(id);
}

static std::string get_lev_string(enum LogMessageLevel lev)
{
	switch(lev){
	case LMT_ERROR:
		return "ERROR";
	case LMT_ACTION:
		return "ACTION";
	case LMT_INFO:
		return "INFO";
	case LMT_VERBOSE:
		return "VERBOSE";
	case LMT_NUM_VALUES:
		break;
	}
	return "(unknown level)";
}

void log_printline(enum LogMessageLevel lev, const std::string &text)
{
	std::string threadname = "(unknown thread)";
	std::map<threadid_t, std::string>::const_iterator i;
	i = log_threadnames.find(get_current_thread_id());
	if(i != log_threadnames.end())
		threadname = i->second;
	std::string levelname = get_lev_string(lev);
	std::ostringstream os(std::ios_base::binary);
	os<<getTimestamp()<<": "<<levelname<<"["<<threadname<<"]: "<<text;
	for(std::list<ILogOutput*>::iterator i = log_outputs[lev].begin();
			i != log_outputs[lev].end(); i++){
		ILogOutput *out = *i;
		out->printLog(os.str());
		out->printLog(os.str(), lev);
		out->printLog(lev, text);
	}
}

class Logbuf : public std::streambuf
{
public:
	Logbuf(enum LogMessageLevel lev):
		m_lev(lev)
	{
	}

	~Logbuf()
	{
	}

	int overflow(int c)
	{
		bufchar(c);
		return c;
	}
	std::streamsize xsputn(const char *s, std::streamsize n)
	{
		for(int i=0; i<n; i++)
			bufchar(s[i]);
		return n;
	}

	void printbuf()
	{
		log_printline(m_lev, m_buf);
	}

	void bufchar(char c)
	{
		if(c == '\n' || c == '\r'){
			if(m_buf != "")
				printbuf();
			m_buf = "";
			return;
		}
		m_buf += c;
	}
	
private:
	enum LogMessageLevel m_lev;
	std::string m_buf;
};

Logbuf errorbuf(LMT_ERROR);
Logbuf actionbuf(LMT_ACTION);
Logbuf infobuf(LMT_INFO);
Logbuf verbosebuf(LMT_VERBOSE);
std::ostream errorstream(&errorbuf);
std::ostream actionstream(&actionbuf);
std::ostream infostream(&infobuf);
std::ostream verbosestream(&verbosebuf);

bool log_trace_level_enabled = false;

ride_jump, float physics_override_gravity) {} virtual void setAnimation(v2f frames, float frame_speed, float frame_blend, bool frame_loop) {} virtual void getAnimation(v2f *frames, float *frame_speed, float *frame_blend, bool *frame_loop) {} virtual void setAnimationSpeed(float frame_speed) {} virtual void setBonePosition(const std::string &bone, v3f position, v3f rotation) {} virtual void getBonePosition(const std::string &bone, v3f *position, v3f *lotation) {} virtual void setAttachment(int parent_id, const std::string &bone, v3f position, v3f rotation) {} virtual void getAttachment(int *parent_id, std::string *bone, v3f *position, v3f *rotation) {} virtual void clearChildAttachments() {} virtual void clearParentAttachment() {} virtual void addAttachmentChild(int child_id) {} virtual void removeAttachmentChild(int child_id) {} virtual const std::unordered_set<int> &getAttachmentChildIds() { static std::unordered_set<int> rv; return rv; } virtual ServerActiveObject *getParent() const { return nullptr; } virtual ObjectProperties* accessObjectProperties() { return NULL; } virtual void notifyObjectPropertiesModified() {} // Inventory and wielded item virtual Inventory* getInventory() { return NULL; } virtual const Inventory* getInventory() const { return NULL; } virtual InventoryLocation getInventoryLocation() const { return InventoryLocation(); } virtual void setInventoryModified() {} virtual std::string getWieldList() const { return ""; } virtual int getWieldIndex() const { return 0; } virtual ItemStack getWieldedItem() const; virtual bool setWieldedItem(const ItemStack &item); inline void attachParticleSpawner(u32 id) { m_attached_particle_spawners.insert(id); } inline void detachParticleSpawner(u32 id) { m_attached_particle_spawners.erase(id); } /* Number of players which know about this object. Object won't be deleted until this is 0 to keep the id preserved for the right object. */ u16 m_known_by_count = 0; /* - Whether this object is to be removed when nobody knows about it anymore. - Removal is delayed to preserve the id for the time during which it could be confused to some other object by some client. - This is usually set to true by the step() method when the object wants to be deleted but can be set by anything else too. */ bool m_pending_removal = false; /* Same purpose as m_pending_removal but for deactivation. deactvation = save static data in block, remove active object If this is set alongside with m_pending_removal, removal takes priority. */ bool m_pending_deactivation = false; /* A getter that unifies the above to answer the question: "Can the environment still interact with this object?" */ inline bool isGone() const { return m_pending_removal || m_pending_deactivation; } /* Whether the object's static data has been stored to a block */ bool m_static_exists = false; /* The block from which the object was loaded from, and in which a copy of the static data resides. */ v3s16 m_static_block = v3s16(1337,1337,1337); /* Queue of messages to be sent to the client */ std::queue<ActiveObjectMessage> m_messages_out; protected: virtual void onAttach(int parent_id) {} virtual void onDetach(int parent_id) {} // Used for creating objects based on type typedef ServerActiveObject* (*Factory) (ServerEnvironment *env, v3f pos, const std::string &data); static void registerType(u16 type, Factory f); ServerEnvironment *m_env; v3f m_base_position; std::unordered_set<u32> m_attached_particle_spawners; private: // Used for creating objects based on type static std::map<u16, Factory> m_types; };