Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
B
beego
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
go
beego
Commits
b19f9bf8
Commit
b19f9bf8
authored
Jan 25, 2016
by
astaxie
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'develop' of
https://github.com/astaxie/beego
into develop
parents
61e9dc74
6cc3d447
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
88 additions
and
60 deletions
+88
-60
config.go
config.go
+13
-1
conn.go
logs/conn.go
+6
-2
console.go
logs/console.go
+4
-2
es.go
logs/es/es.go
+4
-4
file.go
logs/file.go
+4
-40
log.go
logs/log.go
+52
-6
smtp.go
logs/smtp.go
+2
-2
parser.go
parser.go
+3
-3
No files found.
config.go
View file @
b19f9bf8
...
@@ -103,6 +103,8 @@ var (
...
@@ -103,6 +103,8 @@ var (
BConfig
*
Config
BConfig
*
Config
// AppConfig is the instance of Config, store the config information from file
// AppConfig is the instance of Config, store the config information from file
AppConfig
*
beegoAppConfig
AppConfig
*
beegoAppConfig
// AppPath is the absolute path to the app
AppPath
string
// AppConfigPath is the path to the config files
// AppConfigPath is the path to the config files
AppConfigPath
string
AppConfigPath
string
// AppConfigProvider is the provider for the config, default is ini
// AppConfigProvider is the provider for the config, default is ini
...
@@ -111,9 +113,15 @@ var (
...
@@ -111,9 +113,15 @@ var (
TemplateCache
map
[
string
]
*
template
.
Template
TemplateCache
map
[
string
]
*
template
.
Template
// GlobalSessions is the instance for the session manager
// GlobalSessions is the instance for the session manager
GlobalSessions
*
session
.
Manager
GlobalSessions
*
session
.
Manager
workPath
string
)
)
func
init
()
{
func
init
()
{
AppPath
,
_
=
filepath
.
Abs
(
filepath
.
Dir
(
os
.
Args
[
0
]))
workPath
,
_
=
os
.
Getwd
()
workPath
,
_
=
filepath
.
Abs
(
workPath
)
BConfig
=
&
Config
{
BConfig
=
&
Config
{
AppName
:
"beego"
,
AppName
:
"beego"
,
RunMode
:
DEV
,
RunMode
:
DEV
,
...
@@ -181,13 +189,17 @@ func init() {
...
@@ -181,13 +189,17 @@ func init() {
func
ParseConfig
()
(
err
error
)
{
func
ParseConfig
()
(
err
error
)
{
if
AppConfigPath
==
""
{
if
AppConfigPath
==
""
{
// initialize default configurations
// initialize default configurations
AppPath
,
_
:=
filepath
.
Abs
(
filepath
.
Dir
(
os
.
Args
[
0
]))
AppConfigPath
=
filepath
.
Join
(
AppPath
,
"conf"
,
"app.conf"
)
AppConfigPath
=
filepath
.
Join
(
AppPath
,
"conf"
,
"app.conf"
)
if
!
utils
.
FileExists
(
AppConfigPath
)
{
if
!
utils
.
FileExists
(
AppConfigPath
)
{
AppConfig
=
&
beegoAppConfig
{
config
.
NewFakeConfig
()}
AppConfig
=
&
beegoAppConfig
{
config
.
NewFakeConfig
()}
return
return
}
}
}
}
if
workPath
!=
AppPath
{
os
.
Chdir
(
AppPath
)
}
AppConfig
,
err
=
newAppConfig
(
AppConfigProvider
,
AppConfigPath
)
AppConfig
,
err
=
newAppConfig
(
AppConfigProvider
,
AppConfigPath
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
...
...
logs/conn.go
View file @
b19f9bf8
...
@@ -19,6 +19,7 @@ import (
...
@@ -19,6 +19,7 @@ import (
"io"
"io"
"log"
"log"
"net"
"net"
"time"
)
)
// connWriter implements LoggerInterface.
// connWriter implements LoggerInterface.
...
@@ -48,7 +49,7 @@ func (c *connWriter) Init(jsonconfig string) error {
...
@@ -48,7 +49,7 @@ func (c *connWriter) Init(jsonconfig string) error {
// WriteMsg write message in connection.
// WriteMsg write message in connection.
// if connection is down, try to re-connect.
// if connection is down, try to re-connect.
func
(
c
*
connWriter
)
WriteMsg
(
msg
string
,
level
int
)
error
{
func
(
c
*
connWriter
)
WriteMsg
(
when
time
.
Time
,
msg
string
,
level
int
)
error
{
if
level
>
c
.
Level
{
if
level
>
c
.
Level
{
return
nil
return
nil
}
}
...
@@ -62,6 +63,9 @@ func (c *connWriter) WriteMsg(msg string, level int) error {
...
@@ -62,6 +63,9 @@ func (c *connWriter) WriteMsg(msg string, level int) error {
if
c
.
ReconnectOnMsg
{
if
c
.
ReconnectOnMsg
{
defer
c
.
innerWriter
.
Close
()
defer
c
.
innerWriter
.
Close
()
}
}
msg
=
formatLogTime
(
when
)
+
msg
c
.
lg
.
Println
(
msg
)
c
.
lg
.
Println
(
msg
)
return
nil
return
nil
}
}
...
@@ -94,7 +98,7 @@ func (c *connWriter) connect() error {
...
@@ -94,7 +98,7 @@ func (c *connWriter) connect() error {
}
}
c
.
innerWriter
=
conn
c
.
innerWriter
=
conn
c
.
lg
=
log
.
New
(
conn
,
""
,
log
.
Ldate
|
log
.
Ltime
)
c
.
lg
=
log
.
New
(
conn
,
""
,
0
)
return
nil
return
nil
}
}
...
...
logs/console.go
View file @
b19f9bf8
...
@@ -19,6 +19,7 @@ import (
...
@@ -19,6 +19,7 @@ import (
"log"
"log"
"os"
"os"
"runtime"
"runtime"
"time"
)
)
// brush is a color join function
// brush is a color join function
...
@@ -53,7 +54,7 @@ type consoleWriter struct {
...
@@ -53,7 +54,7 @@ type consoleWriter struct {
// NewConsole create ConsoleWriter returning as LoggerInterface.
// NewConsole create ConsoleWriter returning as LoggerInterface.
func
NewConsole
()
Logger
{
func
NewConsole
()
Logger
{
cw
:=
&
consoleWriter
{
cw
:=
&
consoleWriter
{
lg
:
log
.
New
(
os
.
Stdout
,
""
,
log
.
Ldate
|
log
.
Ltime
),
lg
:
log
.
New
(
os
.
Stdout
,
""
,
0
),
Level
:
LevelDebug
,
Level
:
LevelDebug
,
}
}
return
cw
return
cw
...
@@ -69,10 +70,11 @@ func (c *consoleWriter) Init(jsonconfig string) error {
...
@@ -69,10 +70,11 @@ func (c *consoleWriter) Init(jsonconfig string) error {
}
}
// WriteMsg write message in console.
// WriteMsg write message in console.
func
(
c
*
consoleWriter
)
WriteMsg
(
msg
string
,
level
int
)
error
{
func
(
c
*
consoleWriter
)
WriteMsg
(
when
time
.
Time
,
msg
string
,
level
int
)
error
{
if
level
>
c
.
Level
{
if
level
>
c
.
Level
{
return
nil
return
nil
}
}
msg
=
formatLogTime
(
when
)
+
msg
if
goos
:=
runtime
.
GOOS
;
goos
==
"windows"
{
if
goos
:=
runtime
.
GOOS
;
goos
==
"windows"
{
c
.
lg
.
Println
(
msg
)
c
.
lg
.
Println
(
msg
)
return
nil
return
nil
...
...
logs/es/es.go
View file @
b19f9bf8
...
@@ -48,16 +48,16 @@ func (el *esLogger) Init(jsonconfig string) error {
...
@@ -48,16 +48,16 @@ func (el *esLogger) Init(jsonconfig string) error {
}
}
// WriteMsg will write the msg and level into es
// WriteMsg will write the msg and level into es
func
(
el
*
esLogger
)
WriteMsg
(
msg
string
,
level
int
)
error
{
func
(
el
*
esLogger
)
WriteMsg
(
when
time
.
Time
,
msg
string
,
level
int
)
error
{
if
level
>
el
.
Level
{
if
level
>
el
.
Level
{
return
nil
return
nil
}
}
t
:=
time
.
Now
()
vals
:=
make
(
map
[
string
]
interface
{})
vals
:=
make
(
map
[
string
]
interface
{})
vals
[
"@timestamp"
]
=
t
.
Format
(
time
.
RFC3339
)
vals
[
"@timestamp"
]
=
when
.
Format
(
time
.
RFC3339
)
vals
[
"@msg"
]
=
msg
vals
[
"@msg"
]
=
msg
d
:=
goes
.
Document
{
d
:=
goes
.
Document
{
Index
:
fmt
.
Sprintf
(
"%04d.%02d.%02d"
,
t
.
Year
(),
t
.
Month
(),
t
.
Day
()),
Index
:
fmt
.
Sprintf
(
"%04d.%02d.%02d"
,
when
.
Year
(),
when
.
Month
(),
when
.
Day
()),
Type
:
"logs"
,
Type
:
"logs"
,
Fields
:
vals
,
Fields
:
vals
,
}
}
...
...
logs/file.go
View file @
b19f9bf8
...
@@ -114,50 +114,14 @@ func (w *fileLogWriter) needRotate(size int, day int) bool {
...
@@ -114,50 +114,14 @@ func (w *fileLogWriter) needRotate(size int, day int) bool {
}
}
// WriteMsg write logger message into file.
// WriteMsg write logger message into file.
func
(
w
*
fileLogWriter
)
WriteMsg
(
msg
string
,
level
int
)
error
{
func
(
w
*
fileLogWriter
)
WriteMsg
(
when
time
.
Time
,
msg
string
,
level
int
)
error
{
if
level
>
w
.
Level
{
if
level
>
w
.
Level
{
return
nil
return
nil
}
}
//2016/01/12 21:34:33
//2016/01/12 21:34:33
now
:=
time
.
Now
()
// now := time.Now()
y
,
mo
,
d
:=
now
.
Date
()
d
:=
when
.
Day
()
h
,
mi
,
s
:=
now
.
Clock
()
msg
=
formatLogTime
(
when
)
+
msg
+
"
\n
"
//len(2006/01/02 15:03:04)==19
var
buf
[
20
]
byte
t
:=
3
for
y
>=
10
{
p
:=
y
/
10
buf
[
t
]
=
byte
(
'0'
+
y
-
p
*
10
)
y
=
p
t
--
}
buf
[
0
]
=
byte
(
'0'
+
y
)
buf
[
4
]
=
'/'
if
mo
>
9
{
buf
[
5
]
=
'1'
buf
[
6
]
=
byte
(
'0'
+
mo
-
9
)
}
else
{
buf
[
5
]
=
'0'
buf
[
6
]
=
byte
(
'0'
+
mo
)
}
buf
[
7
]
=
'/'
t
=
d
/
10
buf
[
8
]
=
byte
(
'0'
+
t
)
buf
[
9
]
=
byte
(
'0'
+
d
-
t
*
10
)
buf
[
10
]
=
' '
t
=
h
/
10
buf
[
11
]
=
byte
(
'0'
+
t
)
buf
[
12
]
=
byte
(
'0'
+
h
-
t
*
10
)
buf
[
13
]
=
':'
t
=
mi
/
10
buf
[
14
]
=
byte
(
'0'
+
t
)
buf
[
15
]
=
byte
(
'0'
+
mi
-
t
*
10
)
buf
[
16
]
=
':'
t
=
s
/
10
buf
[
17
]
=
byte
(
'0'
+
t
)
buf
[
18
]
=
byte
(
'0'
+
s
-
t
*
10
)
buf
[
19
]
=
' '
msg
=
string
(
buf
[
0
:
])
+
msg
+
"
\n
"
if
w
.
Rotate
{
if
w
.
Rotate
{
if
w
.
needRotate
(
len
(
msg
),
d
)
{
if
w
.
needRotate
(
len
(
msg
),
d
)
{
...
...
logs/log.go
View file @
b19f9bf8
...
@@ -40,6 +40,7 @@ import (
...
@@ -40,6 +40,7 @@ import (
"runtime"
"runtime"
"strconv"
"strconv"
"sync"
"sync"
"time"
)
)
// RFC5424 log message levels.
// RFC5424 log message levels.
...
@@ -68,7 +69,7 @@ type loggerType func() Logger
...
@@ -68,7 +69,7 @@ type loggerType func() Logger
// Logger defines the behavior of a log provider.
// Logger defines the behavior of a log provider.
type
Logger
interface
{
type
Logger
interface
{
Init
(
config
string
)
error
Init
(
config
string
)
error
WriteMsg
(
msg
string
,
level
int
)
error
WriteMsg
(
when
time
.
Time
,
msg
string
,
level
int
)
error
Destroy
()
Destroy
()
Flush
()
Flush
()
}
}
...
@@ -108,6 +109,7 @@ type nameLogger struct {
...
@@ -108,6 +109,7 @@ type nameLogger struct {
type
logMsg
struct
{
type
logMsg
struct
{
level
int
level
int
msg
string
msg
string
when
time
.
Time
}
}
var
logMsgPool
*
sync
.
Pool
var
logMsgPool
*
sync
.
Pool
...
@@ -173,9 +175,9 @@ func (bl *BeeLogger) DelLogger(adapterName string) error {
...
@@ -173,9 +175,9 @@ func (bl *BeeLogger) DelLogger(adapterName string) error {
return
nil
return
nil
}
}
func
(
bl
*
BeeLogger
)
writeToLoggers
(
msg
string
,
level
int
)
{
func
(
bl
*
BeeLogger
)
writeToLoggers
(
when
time
.
Time
,
msg
string
,
level
int
)
{
for
_
,
l
:=
range
bl
.
outputs
{
for
_
,
l
:=
range
bl
.
outputs
{
err
:=
l
.
WriteMsg
(
msg
,
level
)
err
:=
l
.
WriteMsg
(
when
,
msg
,
level
)
if
err
!=
nil
{
if
err
!=
nil
{
fmt
.
Fprintf
(
os
.
Stderr
,
"unable to WriteMsg to adapter:%v,error:%v
\n
"
,
l
.
name
,
err
)
fmt
.
Fprintf
(
os
.
Stderr
,
"unable to WriteMsg to adapter:%v,error:%v
\n
"
,
l
.
name
,
err
)
}
}
...
@@ -183,6 +185,7 @@ func (bl *BeeLogger) writeToLoggers(msg string, level int) {
...
@@ -183,6 +185,7 @@ func (bl *BeeLogger) writeToLoggers(msg string, level int) {
}
}
func
(
bl
*
BeeLogger
)
writeMsg
(
logLevel
int
,
msg
string
)
error
{
func
(
bl
*
BeeLogger
)
writeMsg
(
logLevel
int
,
msg
string
)
error
{
when
:=
time
.
Now
()
if
bl
.
enableFuncCallDepth
{
if
bl
.
enableFuncCallDepth
{
_
,
file
,
line
,
ok
:=
runtime
.
Caller
(
bl
.
loggerFuncCallDepth
)
_
,
file
,
line
,
ok
:=
runtime
.
Caller
(
bl
.
loggerFuncCallDepth
)
if
!
ok
{
if
!
ok
{
...
@@ -196,9 +199,10 @@ func (bl *BeeLogger) writeMsg(logLevel int, msg string) error {
...
@@ -196,9 +199,10 @@ func (bl *BeeLogger) writeMsg(logLevel int, msg string) error {
lm
:=
logMsgPool
.
Get
()
.
(
*
logMsg
)
lm
:=
logMsgPool
.
Get
()
.
(
*
logMsg
)
lm
.
level
=
logLevel
lm
.
level
=
logLevel
lm
.
msg
=
msg
lm
.
msg
=
msg
lm
.
when
=
when
bl
.
msgChan
<-
lm
bl
.
msgChan
<-
lm
}
else
{
}
else
{
bl
.
writeToLoggers
(
msg
,
logLevel
)
bl
.
writeToLoggers
(
when
,
msg
,
logLevel
)
}
}
return
nil
return
nil
}
}
...
@@ -231,7 +235,7 @@ func (bl *BeeLogger) startLogger() {
...
@@ -231,7 +235,7 @@ func (bl *BeeLogger) startLogger() {
for
{
for
{
select
{
select
{
case
bm
:=
<-
bl
.
msgChan
:
case
bm
:=
<-
bl
.
msgChan
:
bl
.
writeToLoggers
(
bm
.
msg
,
bm
.
level
)
bl
.
writeToLoggers
(
bm
.
when
,
bm
.
msg
,
bm
.
level
)
logMsgPool
.
Put
(
bm
)
logMsgPool
.
Put
(
bm
)
}
}
}
}
...
@@ -351,7 +355,7 @@ func (bl *BeeLogger) Close() {
...
@@ -351,7 +355,7 @@ func (bl *BeeLogger) Close() {
for
{
for
{
if
len
(
bl
.
msgChan
)
>
0
{
if
len
(
bl
.
msgChan
)
>
0
{
bm
:=
<-
bl
.
msgChan
bm
:=
<-
bl
.
msgChan
bl
.
writeToLoggers
(
bm
.
msg
,
bm
.
level
)
bl
.
writeToLoggers
(
bm
.
when
,
bm
.
msg
,
bm
.
level
)
logMsgPool
.
Put
(
bm
)
logMsgPool
.
Put
(
bm
)
continue
continue
}
}
...
@@ -362,3 +366,45 @@ func (bl *BeeLogger) Close() {
...
@@ -362,3 +366,45 @@ func (bl *BeeLogger) Close() {
l
.
Destroy
()
l
.
Destroy
()
}
}
}
}
func
formatLogTime
(
when
time
.
Time
)
string
{
y
,
mo
,
d
:=
when
.
Date
()
h
,
mi
,
s
:=
when
.
Clock
()
//len(2006/01/02 15:03:04)==19
var
buf
[
20
]
byte
t
:=
3
for
y
>=
10
{
p
:=
y
/
10
buf
[
t
]
=
byte
(
'0'
+
y
-
p
*
10
)
y
=
p
t
--
}
buf
[
0
]
=
byte
(
'0'
+
y
)
buf
[
4
]
=
'/'
if
mo
>
9
{
buf
[
5
]
=
'1'
buf
[
6
]
=
byte
(
'0'
+
mo
-
9
)
}
else
{
buf
[
5
]
=
'0'
buf
[
6
]
=
byte
(
'0'
+
mo
)
}
buf
[
7
]
=
'/'
t
=
d
/
10
buf
[
8
]
=
byte
(
'0'
+
t
)
buf
[
9
]
=
byte
(
'0'
+
d
-
t
*
10
)
buf
[
10
]
=
' '
t
=
h
/
10
buf
[
11
]
=
byte
(
'0'
+
t
)
buf
[
12
]
=
byte
(
'0'
+
h
-
t
*
10
)
buf
[
13
]
=
':'
t
=
mi
/
10
buf
[
14
]
=
byte
(
'0'
+
t
)
buf
[
15
]
=
byte
(
'0'
+
mi
-
t
*
10
)
buf
[
16
]
=
':'
t
=
s
/
10
buf
[
17
]
=
byte
(
'0'
+
t
)
buf
[
18
]
=
byte
(
'0'
+
s
-
t
*
10
)
buf
[
19
]
=
' '
return
string
(
buf
[
0
:
])
}
logs/smtp.go
View file @
b19f9bf8
...
@@ -126,7 +126,7 @@ func (s *SMTPWriter) sendMail(hostAddressWithPort string, auth smtp.Auth, fromAd
...
@@ -126,7 +126,7 @@ func (s *SMTPWriter) sendMail(hostAddressWithPort string, auth smtp.Auth, fromAd
// WriteMsg write message in smtp writer.
// WriteMsg write message in smtp writer.
// it will send an email with subject and only this message.
// it will send an email with subject and only this message.
func
(
s
*
SMTPWriter
)
WriteMsg
(
msg
string
,
level
int
)
error
{
func
(
s
*
SMTPWriter
)
WriteMsg
(
when
time
.
Time
,
msg
string
,
level
int
)
error
{
if
level
>
s
.
Level
{
if
level
>
s
.
Level
{
return
nil
return
nil
}
}
...
@@ -140,7 +140,7 @@ func (s *SMTPWriter) WriteMsg(msg string, level int) error {
...
@@ -140,7 +140,7 @@ func (s *SMTPWriter) WriteMsg(msg string, level int) error {
// and send the email all in one step.
// and send the email all in one step.
contentType
:=
"Content-Type: text/plain"
+
"; charset=UTF-8"
contentType
:=
"Content-Type: text/plain"
+
"; charset=UTF-8"
mailmsg
:=
[]
byte
(
"To: "
+
strings
.
Join
(
s
.
RecipientAddresses
,
";"
)
+
"
\r\n
From: "
+
s
.
FromAddress
+
"<"
+
s
.
FromAddress
+
mailmsg
:=
[]
byte
(
"To: "
+
strings
.
Join
(
s
.
RecipientAddresses
,
";"
)
+
"
\r\n
From: "
+
s
.
FromAddress
+
"<"
+
s
.
FromAddress
+
">
\r\n
Subject: "
+
s
.
Subject
+
"
\r\n
"
+
contentType
+
"
\r\n\r\n
"
+
fmt
.
Sprintf
(
".%s"
,
time
.
Now
()
.
Format
(
"2006-01-02 15:04:05"
))
+
msg
)
">
\r\n
Subject: "
+
s
.
Subject
+
"
\r\n
"
+
contentType
+
"
\r\n\r\n
"
+
fmt
.
Sprintf
(
".%s"
,
when
.
Format
(
"2006-01-02 15:04:05"
))
+
msg
)
return
s
.
sendMail
(
s
.
Host
,
auth
,
s
.
FromAddress
,
s
.
RecipientAddresses
,
mailmsg
)
return
s
.
sendMail
(
s
.
Host
,
auth
,
s
.
FromAddress
,
s
.
RecipientAddresses
,
mailmsg
)
}
}
...
...
parser.go
View file @
b19f9bf8
...
@@ -130,7 +130,7 @@ func parserComments(comments *ast.CommentGroup, funcName, controllerName, pkgpat
...
@@ -130,7 +130,7 @@ func parserComments(comments *ast.CommentGroup, funcName, controllerName, pkgpat
}
}
func
genRouterCode
()
{
func
genRouterCode
()
{
os
.
Mkdir
(
"routers"
,
0755
)
os
.
Mkdir
(
path
.
Join
(
AppPath
,
"routers"
)
,
0755
)
Info
(
"generate router from comments"
)
Info
(
"generate router from comments"
)
var
(
var
(
globalinfo
string
globalinfo
string
...
@@ -172,7 +172,7 @@ func genRouterCode() {
...
@@ -172,7 +172,7 @@ func genRouterCode() {
}
}
}
}
if
globalinfo
!=
""
{
if
globalinfo
!=
""
{
f
,
err
:=
os
.
Create
(
path
.
Join
(
"routers"
,
commentFilename
))
f
,
err
:=
os
.
Create
(
path
.
Join
(
AppPath
,
"routers"
,
commentFilename
))
if
err
!=
nil
{
if
err
!=
nil
{
panic
(
err
)
panic
(
err
)
}
}
...
@@ -182,7 +182,7 @@ func genRouterCode() {
...
@@ -182,7 +182,7 @@ func genRouterCode() {
}
}
func
compareFile
(
pkgRealpath
string
)
bool
{
func
compareFile
(
pkgRealpath
string
)
bool
{
if
!
utils
.
FileExists
(
path
.
Join
(
"routers"
,
commentFilename
))
{
if
!
utils
.
FileExists
(
path
.
Join
(
AppPath
,
"routers"
,
commentFilename
))
{
return
true
return
true
}
}
if
utils
.
FileExists
(
lastupdateFilename
)
{
if
utils
.
FileExists
(
lastupdateFilename
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment